我遇到了这段代码,我很惊讶它在列表中添加了一个元素。
代码如下:
class Wrapper:
def __init__(self, object):
self.wrapped = object
def __getattr__(self,attrname):
print('Trace: '+attrname)
return getattr(self.wrapped,attrname)
X = Wrapper([1,2,3])
X.append(4)
print(X.wrapped)
我很惊讶,因为如果我运行type(X)
会得到__main__.Wrapper
,这很有意义,因为X
是类Wrapper
的对象。因此,我不确定为什么X.append
直接添加到属性wrapped
的列表中。毕竟,X
的类型不是list
,而是Wrapper.
呼叫不是X.wrapped.append(4)
吗?这也可以。
我是初学者,这可能是一个基本问题。我将不胜感激,感谢您的帮助。
此代码从Mark Lutz的书中采用。我正在使用Anaconda 3.6发行版
答案 0 :(得分:1)
此类仅在访问对象的原始属性之前添加一条打印语句。
要了解其工作原理,您必须对__getattr__
的工作有所了解。这些方法的文档在Python手册的data model section下:
在默认属性访问失败并带有
AttributeError
时调用 (__getattribute__()
都会引发AttributeError
,因为名称是 不是实例属性或类树中用于自身的属性; 或名称属性的__get__()
引发AttributeError
)。这个方法 应该返回(计算出的)属性值或引发AttributeError
例外。
当您编写如下语句时,.
(点)运算符实际上是搜索或查找运算符:
foo.append(x)
您和我理解这表示“用参数x调用foo对象的append方法”-Python试图在foo对象上搜索属性“ append”,然后尝试用参数调用它的 x 。
在自定义对象中,我们没有append
属性,该属性会触发__getattr__
调用。
然后我们拦截对__getattr__
的调用,打印出一条调试语句,然后将此调用传递给实际的对象(在self.wrapped
中对此对象的引用)。
简而言之,我们说-嘿-我们了解包装器对象没有此属性,但是尝试通过调用其__getattr__
来查看包装的对象是否具有代替。
这种沿调用链传递的概念可提供灵活性,因为我们可以模仿原始(包装的)对象的作用-使包装程序非常通用。即使您传入了字符串或任何其他Python对象,它也将起作用。
答案 1 :(得分:0)
__getattr__
是magic method的运算符重载attribute reference .
operator。还有其他几种方法可以执行此操作,例如针对单个属性的descriptors或甚至覆盖现有属性的__getattribute__
。