python中非常奇怪的__getattr__行为

时间:2014-12-03 06:00:54

标签: python python-2.7

我的代码出错(类似于下面的错误),但结果对我来说似乎很奇怪。有人可以向我解释 getattr 是如何调用名称为"你好"?

class A(object):
    def __getattr__(self, name):
        print name
        assert name != 'hello'
        return self.hello

class C(object):
    def __init__(self):
        class B(A):
            @property
            def hello(self_):
                return self.durp

        self.b = B()

c = C()
print c.b.bang

这个输出是:

bang
hello
Traceback (most recent call last):
  File "test.py", line 17, in <module>
    print c.b.bang
  File "test.py", line 5, in __getattr__
    return self.hello
  File "test.py", line 4, in __getattr__
    assert name != 'hello'
AssertionError

shell returned 1

我当然理解C中没有durp属性(这是我所说的错误)。但是,我不希望用hello作为字符串调用__getattr__。我觉得我不理解__getattr__的工作原理。

2 个答案:

答案 0 :(得分:5)

通过&#34;通常的方法访问属性时调用

__getattr__&#34;失败。 Python知道是否&#34;通常的方法&#34;失败的是引发了AttributeError。但是,它无法判断是否在尝试获取您尝试获取的原始属性时引发了此AttributeError,或者在该过程中访问了某些其他属性。所以发生了什么:

  1. Python尝试访问c.b.bang
  2. b对象没有属性&#34; bang&#34;所以__getattr__被调用。
  3. __getattr__尝试获取self.hello
  4. Python找到属性hello,其值为属性
  5. 在尝试评估self.hello时,Python运行hello属性。
  6. 运行hello属性会尝试访问不存在的属性durp。这引发了一个AttributeError
  7. 因为在尝试评估self.hello时引发了AttributeError,Python认为通过&#34;通常的方法&#34;没有这样的属性可用。因此,它用&#34;你好&#34;来调用__getattr__。作为论点。
  8. 这种行为令人困惑,但基本上是Python中属性查找工作方式的不可避免的副作用。知道&#34;正常属性查找没有工作的唯一方法&#34;是引发了AttributeError。关于此问题有a Python bug,显然人们仍然在努力,但到目前为止还没有真正的解决方案。

答案 1 :(得分:-1)

return self.hello

的定义中的

a.__getattr__

class A(object):
    def __getattr__(self, name):
        print name
        assert name != 'hello'
        return self.hello

触发新的属性搜索,这次使用'hello'作为name参数的值,这会导致您的断言失败