简体   繁体   English

python中非常奇怪的__getattr__行为

[英]Very strange __getattr__ behavior in python

I had an error in my code (similar to the error below) but the result seems very strange to me. 我的代码中有一个错误(类似于下面的错误),但结果对我来说似乎很奇怪。 Can someone explain to me how getattr is getting called with the name being "hello"? 有人可以给我解释一下名称为“ hello”的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

The output of this is: 输出为:

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

I understand of course that there is no durp property in C (this is the error I speak of). 我当然知道C中没有durp属性(这是我所说的错误)。 However, I would not expect __getattr__ to be called with hello as the string. 但是,我不希望以hello作为字符串调用__getattr__ I feel like I'm not understanding something fundamental about the way __getattr__ works. 我觉得我不太了解__getattr__工作原理。

__getattr__ is called when accessing an attribute via "the usual methods" fails. 通过“常用方法”访问属性失败时,将调用__getattr__ The way Python knows whether "the usual methods" have failed is that an AttributeError is raised. Python知道“常规方法”是否失败的方式是引发AttributeError。 It can't tell, though, whether this AttributeError was raised in trying to get the original attribute you were trying to get, or some other attribute accessed as part of that process. 但是,它无法确定是在尝试获取要获取的原始属性时引发了此AttributeError,还是在该过程中访问了某些其他属性。 So here's what happens: 所以这是发生了什么:

  1. Python tries to access cbbang Python尝试访问cbbang
  2. the b object has no attribute "bang" so the __getattr__ is called. b对象没有属性“ bang”,因此调用__getattr__
  3. the __getattr__ tries to get self.hello __getattr__尝试获取self.hello
  4. Python finds the attribute hello , whose value is a property Python找到属性hello ,其值是一个属性
  5. In trying to evaluate self.hello , Python runs the hello property. 在尝试评估self.hello ,Python运行hello属性。
  6. Running the hello property tries to access a nonexistent attribute durp . 运行hello属性会尝试访问不存在的属性durp This raises an AttributeError 这引发了AttributeError
  7. Because an AttributeError was raised as part of trying to evaluate self.hello , Python thinks there is no such attribute available via "the usual methods". 因为在尝试评估self.hello引发了AttributeError,所以Python认为没有可通过“常规方法”获得的此类属性。 It therefore calls __getattr__ with "hello" as the argument. 因此,它将使用“ hello”作为参数调用__getattr__

This behavior is confusing, but is basically an unavoidable side effect of how attribute lookup in Python works. 这种行为令人困惑,但是从根本上来说,这是Python中属性查找如何工作的不可避免的副作用。 The only way to know that "normal attribute lookup didn't work" is that an AttributeError was raised. 知道“常规属性查找无效”的唯一方法是引发了AttributeError。 There is a Python bug about this, which apparently people are still working on, but no real solution exists so far. 一个关于此的Python错误 ,显然人们仍在研究,但到目前为止尚无真正的解决方案。

return self.hello in the definition of a.__getattr__ a.__getattr__的定义中return self.hello a.__getattr__

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

triggers a new attribute search, this time with 'hello' as the value of the name parameter, which causes your assertion to fail 触发新的属性搜索,这次使用'hello'作为name参数的值,这会导致断言失败

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM