Python中的实例类型

时间:2018-07-15 05:34:22

标签: python python-3.x list types

我遇到了这段代码,我很惊讶它在列表中添加了一个元素。

代码如下:

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发行版

2 个答案:

答案 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__