使用 __getattr__() 和 __setattr__() 提供多种访问 child 变量的方法
Using __getattr__() and __setattr__() to provide multiple ways to access child variables
尊敬的同事们!
请考虑...
#!/usr/bin/env python3.6
class Child(object):
def __init__(self, name:str, value = 0):
self.name = name;
self.value = value;
def __repr__(self):
return ' child "{}" has value {}\n'.format(self.name, self.value)
class Parent(object):
def __init__(self, name:str):
self.name = name
self.children = {}
def __repr__(self):
s = 'Parent "{}":\n'.format(self.name)
for k, v in self.children.items():
s += v.__repr__()
return s
def __getattr__(self, name:str):
if name == 'children':
return self.children;
elif name in self.children.keys():
return self.children[name].value
else:
return super().__getattr__(name)
def __setattr__(self, prop, val):
if prop == 'name':
super().__setattr__(prop, val)
else:
super().__setattr__('children[{}]'.format(prop), val)
p = Parent('Tango')
p.children['Alfa'] = Child('Alfa', 55)
p.children['Bravo'] = Child('Bravo', 66)
print(p)
print(p.children['Alfa']) # Returns '55' (normal)
print(p.Alfa) # Returns '55' (__getattr__)
print('-----')
p.Alfa = 99 # This is creating a new variable, need __setattr__ ...
print(p.Alfa) # Prints new variable. __setattr__ is not called!
print('-----')
print(p.children['Alfa']) # Still '55'
print(p) # Still '55'
代码的目的是让持有 Parent
的人可以通过两种方式访问其 children
:p.children['Alfa']
或 p.Alfa
。
使用__getattr__()
我可以完成这个read-side。 (注释掉上面代码中的 def __setattr__()
,您可以看到 read-side 按预期工作。)输出 without setattr() 是:
Parent "Tango":
child "Alfa" has value 55
child "Bravo" has value 66
child "Alfa" has value 55
55
-----
99
-----
child "Alfa" has value 55
Parent "Tango":
child "Alfa" has value 55
child "Bravo" has value 66
当然现在我需要__setattr__()
来完成这个write-side。我想将 99 分配给阿尔法。到现在还没想出避免各种问题的咒语
上面的代码 with setattr() 引发 RecursionError
:
Traceback (most recent call last):
File "./test.py", line 37, in <module>
p.children['Alfa'] = Child('Alfa', 55)
File "./test.py", line 23, in __getattr__
return self.children;
File "./test.py", line 23, in __getattr__
return self.children;
File "./test.py", line 23, in __getattr__
return self.children;
[Previous line repeated 328 more times]
File "./test.py", line 22, in __getattr__
if name == 'children':
RecursionError: maximum recursion depth exceeded in comparison
我希望后面的 测试代码 表明通过写入 p.Alfa
,我实际上是在更新 self.children['Alfa']
的值。赋值后打印出来应该是99,不是原来的55.
请注意,在现实世界中,可能的 children、它们的名称和内容几乎是无限的。
感谢您的帮助和见解!
def __setattr__(self, attr, val):
if attr == 'name':
super().__setattr__(self, 'name', val)
return
self.children[attr] = val
您的代码从不初始化名为 children
的属性。它初始化一个名为 children[children]
的对象。因此,当您稍后尝试分配给 self.children['Alfa']
时,它尝试做的第一件事就是找到一个名为 children
的属性。当找不到时,它调用__getattr__
,它说当name == "children"
时,它应该return self.children
,然后无限循环开始。
__getattr__
仅 在通过正常过程找不到属性时调用。正确定义 __setattr__
后,永远不应为 children
调用 __getattr__
,因为您在 __init__
中定义了它。定义可以简化为
def __getattr__(self, name:str):
if name in self.children.keys():
return self.children[name].value
else:
return super().__getattr__(name)
尊敬的同事们!
请考虑...
#!/usr/bin/env python3.6
class Child(object):
def __init__(self, name:str, value = 0):
self.name = name;
self.value = value;
def __repr__(self):
return ' child "{}" has value {}\n'.format(self.name, self.value)
class Parent(object):
def __init__(self, name:str):
self.name = name
self.children = {}
def __repr__(self):
s = 'Parent "{}":\n'.format(self.name)
for k, v in self.children.items():
s += v.__repr__()
return s
def __getattr__(self, name:str):
if name == 'children':
return self.children;
elif name in self.children.keys():
return self.children[name].value
else:
return super().__getattr__(name)
def __setattr__(self, prop, val):
if prop == 'name':
super().__setattr__(prop, val)
else:
super().__setattr__('children[{}]'.format(prop), val)
p = Parent('Tango')
p.children['Alfa'] = Child('Alfa', 55)
p.children['Bravo'] = Child('Bravo', 66)
print(p)
print(p.children['Alfa']) # Returns '55' (normal)
print(p.Alfa) # Returns '55' (__getattr__)
print('-----')
p.Alfa = 99 # This is creating a new variable, need __setattr__ ...
print(p.Alfa) # Prints new variable. __setattr__ is not called!
print('-----')
print(p.children['Alfa']) # Still '55'
print(p) # Still '55'
代码的目的是让持有 Parent
的人可以通过两种方式访问其 children
:p.children['Alfa']
或 p.Alfa
。
使用__getattr__()
我可以完成这个read-side。 (注释掉上面代码中的 def __setattr__()
,您可以看到 read-side 按预期工作。)输出 without setattr() 是:
Parent "Tango":
child "Alfa" has value 55
child "Bravo" has value 66
child "Alfa" has value 55
55
-----
99
-----
child "Alfa" has value 55
Parent "Tango":
child "Alfa" has value 55
child "Bravo" has value 66
当然现在我需要__setattr__()
来完成这个write-side。我想将 99 分配给阿尔法。到现在还没想出避免各种问题的咒语
上面的代码 with setattr() 引发 RecursionError
:
Traceback (most recent call last):
File "./test.py", line 37, in <module>
p.children['Alfa'] = Child('Alfa', 55)
File "./test.py", line 23, in __getattr__
return self.children;
File "./test.py", line 23, in __getattr__
return self.children;
File "./test.py", line 23, in __getattr__
return self.children;
[Previous line repeated 328 more times]
File "./test.py", line 22, in __getattr__
if name == 'children':
RecursionError: maximum recursion depth exceeded in comparison
我希望后面的 测试代码 表明通过写入 p.Alfa
,我实际上是在更新 self.children['Alfa']
的值。赋值后打印出来应该是99,不是原来的55.
请注意,在现实世界中,可能的 children、它们的名称和内容几乎是无限的。
感谢您的帮助和见解!
def __setattr__(self, attr, val):
if attr == 'name':
super().__setattr__(self, 'name', val)
return
self.children[attr] = val
您的代码从不初始化名为 children
的属性。它初始化一个名为 children[children]
的对象。因此,当您稍后尝试分配给 self.children['Alfa']
时,它尝试做的第一件事就是找到一个名为 children
的属性。当找不到时,它调用__getattr__
,它说当name == "children"
时,它应该return self.children
,然后无限循环开始。
__getattr__
仅 在通过正常过程找不到属性时调用。正确定义 __setattr__
后,永远不应为 children
调用 __getattr__
,因为您在 __init__
中定义了它。定义可以简化为
def __getattr__(self, name:str):
if name in self.children.keys():
return self.children[name].value
else:
return super().__getattr__(name)