内容简介:去年我写过一篇今天又遇到了一个 AttributeError 向上传播的问题 (Python 2),一起来看看先上代码:
前言
去年我写过一篇 你用对 hasattr 了嘛? 介绍过被 property 装饰的方法内部抛错会引起 hasattr 的结果为 False。
今天又遇到了一个 AttributeError 向上传播的问题 (Python 2),一起来看看
问题
先上代码:
In : class T(object):
...: @property
...: def name(self):
...: print(self.missing_attribute)
...: return 42
...: def __getattr__(self, name):
...: raise AttributeError(name)
...:
In : t = T()
In : t.name
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-6-afc812d51b9a> in <module>()
----> 1 t.name
<ipython-input-4-a0ba2d3a6446> in __getattr__(self, name)
5 return 42
6 def __getattr__(self, name):
----> 7 raise AttributeError(name)
8
AttributeError: name
In : [k for k in dir(t) if not k.startswith('_')]
Out: ['name']
这个例子需要细品,明明有 name 这个属性却抛出了 AttributeError。分析一下:
-
通过
__getattr__定制属性查找的逻辑,当用户试图获取一个不存在的属性时就会抛 AttributeError 错误 -
获取 name 属性的逻辑中包含
print (self.missing_attribute)这句,由于没有这个属性会执行到__getattr__然后抛 AttributeError
一看到这个违背常理的错误,我就想起来 hasattr 的那个问题,觉得应该是类似的原因。网上一搜果然之前有人已经给 CPython 提过 issue 了,具体可以看延伸阅读链接。总结一下,这个问题的出现需要有 2 个点都满足:
__getattr__
相当于方法中的 AttributeError 没有被处理,传播到 __getattr__
了。再看一个例子:
In : class T(object):
...: @property
...: def name(self):
...: raise AttributeError('This message will not be displayed!')
...: return 'Hello'
...: def __getattr__(self, name):
...: return 0
...:
In : t = T()
In : t.name
Out: 0
一旦 name 方法中由于各种原因会抛 AttributeError 错误 (别的错误不行),就会走 __getattr__
里面的逻辑。
怎么解决?
这不是一个 BUG,但是代码编写者不能规避这类问题,怎么办呢?最简单的办法是使用 __getattribute__
替代 __getattr__
,演示一下:
In : class T(object):
...: @property
...: def name(self):
...: raise AttributeError('This message will not be displayed!')
...: return 'Hello'
...:
...: def __getattribute__(self, name):
...: try:
...: return super(T, self).__getattribute__(name)
...: except AttributeError as e:
...: raise e
...:
In : t = T()
In : t.name
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-28-afc812d51b9a> in <module>()
----> 1 t.name
<ipython-input-26-a27dd1330f44> in __getattribute__(self, name)
9 return super(T, self).__getattribute__(name)
10 except AttributeError as e:
---> 11 raise e
12
AttributeError: This message will not be displayed!
In : class T(object):
...: @property
...: def name(self):
...: print(self.missing_attribute)
...: return 42
...: def __getattribute__(self, name):
...: try:
...: return super(T, self).__getattribute__(name)
...: except AttributeError as e:
...: raise e
...:
In : t = T()
In : t.name
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-31-afc812d51b9a> in <module>()
----> 1 t.name
<ipython-input-29-da47b1a1e093> in __getattribute__(self, name)
8 return super(T, self).__getattribute__(name)
9 except AttributeError as e:
---> 10 raise e
11
AttributeError: 'T' object has no attribute 'missing_attribute'
就是这样~
延伸阅读
以上所述就是小编给大家介绍的《property的AttributeError的传播问题》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C和C++代码精粹
阿林森 / 董慧颖 / 人民邮电出版社 / 2003-4-1 / 59.00
《C和C++代码精粹》基于作者备受好评的C/C++ User Journal杂志上的每月专栏,通过大量完全符合ISO标准C++的程序集合,说明了C++真正强大的威力,是C和C++职业程序员的实践指南。可以帮助有一定经验的C和C++程序员深入学习这两种密切相关的语言,对书中代码的参悟和应用,可以帮助他们从根本上提高使用程序的效率。一起来看看 《C和C++代码精粹》 这本书的介绍吧!