代码之家  ›  专栏  ›  技术社区  ›  watchtower

python中的实例类型

  •  1
  • watchtower  · 技术社区  · 8 年前

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

    代码如下:

    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 直接的。毕竟, 十 不是 list 但是 Wrapper.

    不该打电话 X.wrapped.append(4) 是吗?这也行。

    我是个初学者,这可能是一个基本的问题。我很感激你的任何想法,谢谢你的帮助。


    这个密码是从马克·鲁兹的书中采用的。我用的是水蟒3.6版

    2 回复  |  直到 8 年前
        1
  •  1
  •   Burhan Khalid    8 年前

    这个类只是在访问对象的原始属性之前添加一个print语句。

    要了解这是如何工作的,你必须了解 __getattr__ 做。这些方法的文档位于 data model section 在python手册中:

    当默认属性访问失败时调用 AttributeError (或者 __getattribute__() 提出 属性错误 因为名字是 不是实例属性,也不是类树中的自我属性; 或 __get__() 属性引发的 属性错误 )中。这种方法 应返回(计算的)属性值或引发 属性错误 例外。

    这个 . (点)运算符实际上是一个搜索或查找运算符,当您编写如下语句时:

    foo.append(x)
    

    您和我理解这意味着“使用参数x调用foo对象的append方法”-python试图在foo对象上搜索属性“append”,然后尝试使用参数 十 是的。

    在自定义对象中,我们没有 append 属性,它触发 _获取属性__ 打电话来。

    然后我们拦截这个呼叫 _获取属性__ ,打印出调试语句,然后将此调用传递给实际对象(对它的引用位于 self.wrapped )中。

    简而言之,我们是说-嘿-我们知道我们的包装器对象没有这个属性,但是 试试看包装的对象是否 ,通过调用 _获取属性__ 相反。

    通过调用链的这个概念允许我们模仿原始的(包装的)对象所做的灵活性,使我们的包装非常通用。即使传入了字符串或任何其他python对象,它也可以工作。

        2
  •  0
  •   gilch    8 年前

    这个 __getattr__ 是操作员过载 magic method 对于 attribute reference . operator 是的。有其他几种方法可以做到这一点,比如 descriptors 对于单个属性或 __getattribute__ 它甚至覆盖了现有的属性。