Cla*_*diu 6 python object magic-methods getattr getattribute
我想写一个包装类,除了添加'reason'属性之外,它取一个值并且表现得像它一样.我有这样的想法:
class ExplainedValue(object):
def __init__(self, value, reason):
self.value = value
self.reason = reason
def __getattribute__(self, name):
print '__getattribute__ with %s called' % (name,)
if name in ('__str__', '__repr__', 'reason', 'value'):
return object.__getattribute__(self, name)
value = object.__getattribute__(self, 'value')
return object.__getattribute__(value, name)
def __str__(self):
return "ExplainedValue(%s, %s)" % (
str(self.value),
self.reason)
__repr__ = __str__
Run Code Online (Sandbox Code Playgroud)
但是,双下划线函数似乎没有被捕获__getattribute__,例如:
>>> numbers = ExplainedValue([1, 2, 3, 4], "it worked")
>>> numbers[0]
Traceback (most recent call last):
File "<pyshell#118>", line 1, in <module>
numbers[0]
TypeError: 'ExplainedValue' object does not support indexing
>>> list(numbers)
__getattribute__ with __class__ called
Traceback (most recent call last):
File "<pyshell#119>", line 1, in <module>
list(numbers)
TypeError: 'ExplainedValue' object is not iterable
Run Code Online (Sandbox Code Playgroud)
我认为上述两个应该最终做到这一点:
>>> numbers.value[0]
__getattribute__ with value called
1
>>> list(numbers.value)
__getattribute__ with value called
[1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)
为什么这不会发生?我怎样才能实现呢?(这可能是真正用于实际代码的一个可怕的想法,但我现在对技术问题感到好奇.)
正如millimoose所说,一个隐含的__foo__呼叫永远不会通过__getattribute__.你唯一能做的就是在你的包装类中添加适当的函数.
class Wrapper(object):
def __init__(self, wrapped):
self.wrapped = wrapped
for dunder in ('__add__', '__sub__', '__len__', ...):
locals()[dunder] = lambda self, __f=dunder, *args, **kwargs: getattr(self.wrapped, __f)(*args, **kwargs)
obj = [1,2,3]
w = Wrapper(obj)
print len(w)
Run Code Online (Sandbox Code Playgroud)
类主体像任何其他块一样执行代码(好吧,除外def); 你可以把循环和其他任何你想要的东西放在里面.它们只是神奇的,因为整个局部范围被传递到type()块的末尾以创建类.
这也许是唯一一种分配到locals()甚至远程有用的情况.