2014-12-03 152 views
1

我的代码有错误(类似于下面的错误),但结果对我来说似乎很奇怪。有人可以向我解释如何调用getattr的名称是“hello”吗?python中很奇怪的__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财产。不过,我不希望__getattr__作为字符串使用hello来调用。我觉得我对__getattr__的工作方式并不了解。

回答

4

__getattr__当通过“通常的方法”访问属性失败时被调用。 Python知道“常用方法”是否失败的方式是引发了一个AttributeError。但是,它不能说明这个AttributeError是在尝试获取您尝试获取的原始属性时引发的,还是在作为该流程的一部分访问的其他属性时引发的。因此,这里是发生了什么:

  1. 的Python试图访问c.b.bang
  2. B对象有没有属性“砰”所以__getattr__被调用。
  3. __getattr__试图得到self.hello
  4. Python中找到属性hello,它的值是一个属性
  5. 在试图评估self.hello,Python的运行hello财产。
  6. 运行hello属性会尝试访问不存在的属性durp。这引发了一个AttributeError
  7. 因为AttributeError是作为试图评估self.hello的一部分引发的,所以Python认为通过“通常的方法”没有可用的这样的属性。因此它以“hello”作为参数调用__getattr__

这种行为令人困惑,但基本上是Python中属性查找工作的一个不可避免的副作用。知道“正常属性查找不起作用”的唯一方法是引发了一个AttributeError。有关于此的a Python bug,显然人们仍在努力,但到目前为止还没有真正的解决方案。

+0

所以基本上C类创建一个AttributeError异常,因为在C中没有__getattr__它只是碰到没有得到“过时”而A会尝试处理它,因为有一个异常,即使它不是源于A类的,也是跛脚。似乎是一种奇怪的方式来确定“常用方法”失败,但这肯定会解释发生了什么。 – CrazyCasta 2014-12-03 07:26:07

-1

a.__getattr__

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

定义return self.hello触发一个新的属性的搜索,这一次'hello'name参数的值,这会导致你的断言失败

+0

如果我在hello属性中没有错误,断言永远不会失败,因为__getattr__永远不会被“hello”字符串调用。从概念上讲,它不应该被调用,因为hello属性存在,但正如BrenBarn解释python在处理“常规方法失败”方法时有点奇怪,所以A类试图处理C类的不存在属性。 – CrazyCasta 2014-12-03 07:28:59

+0

感谢评论中的更正,BrenBarn是正确的 – 2014-12-03 18:10:11