Python hasattr 与 getattr
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24971061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python hasattr vs getattr
提问by raulcumplido
I have been reading lately some tweetsand the python documentationabout hasattr and it says:
我最近一直在阅读一些关于 hasattr 的推文和python 文档,它说:
hasattr(object, name)
The arguments are an object and a string. The result is True if the string is the name of >> one of the object's attributes, False if not. (This is implemented by calling getattr(object, name) and seeing whether it raises an AttributeError or not.)
hasattr(对象,名称)
参数是一个对象和一个字符串。如果字符串是对象属性之一的名称,则结果为 True,否则为 False。(这是通过调用 getattr(object, name) 并查看它是否引发 AttributeError 来实现的。)
There is a motto in Python that says that is Easier to ask for forgiveness than permissionwhere I usually agree.
Python 中有一句格言说请求宽恕比我通常同意的许可更容易。
I tried to do a performance test in this case with a really simple python code:
在这种情况下,我尝试使用非常简单的 python 代码进行性能测试:
import timeit
definition="""\
class A(object):
a = 1
a = A()
"""
stm="""\
hasattr(a, 'a')
"""
print timeit.timeit(stmt=stm, setup=definition, number=10000000)
stm="""\
getattr(a, 'a')
"""
print timeit.timeit(stmt=stm, setup=definition, number=10000000)
With the results:
结果:
$ python test.py
hasattr(a, 'a')
1.26515984535
getattr(a, 'a')
1.32518696785
I′ve tried also what happens if the attribute doesn′t exists and the differences between getattr and hasattr are bigger. So what I′ve seen so far is that getattr is slower than hasattr, but in the documentation it says that it calls getattr.
我也试过如果属性不存在并且 getattr 和 hasattr 之间的差异更大会发生什么。所以到目前为止我所看到的是 getattr 比 hasattr 慢,但是在文档中它说它调用了 getattr。
I′ve searched the CPython implementation of hasattrand getattrand it seems that both call the next function:
我搜索了hasattr和getattr的 CPython 实现,似乎都调用了下一个函数:
v = PyObject_GetAttr(v, name);
but there is more boilerplate in getattr than in hasattr that probably makes it slower.
但是 getattr 中的样板比 hasattr 中的更多,这可能会使它变慢。
Does anyone knows why in the documentation we say that hasattr calls getattr and we seem to encourage the users to use getattr instead of hasattr when it really isn′t due to performance? Is just because it is more pythonic?
有谁知道为什么在文档中我们说 hasattr 调用 getattr 并且我们似乎鼓励用户使用 getattr 而不是 hasattr 当它确实不是由于性能原因时?仅仅是因为它更pythonic吗?
Maybe I am doing something wrong in my test :)
也许我在测试中做错了什么:)
Thanks,
谢谢,
Raúl
劳尔
回答by Antti Haapala
The documentation does not encourage, the documentation just states the obvious. The hasattr
is implemented as such, and throwing an AttributeError
from a property getter can make it look like the attribute does not exist. This is an important detail, and that is why it is explicitly stated in the documentation. Consider for example this code:
文档不鼓励,文档只是说明了显而易见的事情。在hasattr
被实现为这样的,并抛出一个AttributeError
从属性的getter可以使它看起来像属性不存在。这是一个重要的细节,这就是为什么在文档中明确说明的原因。例如,考虑以下代码:
class Spam(object):
sausages = False
@property
def eggs(self):
if self.sausages:
return 42
raise AttributeError("No eggs without sausages")
@property
def invalid(self):
return self.foobar
spam = Spam()
print(hasattr(Spam, 'eggs'))
print(hasattr(spam, 'eggs'))
spam.sausages = True
print(hasattr(spam, 'eggs'))
print(hasattr(spam, 'invalid'))
The result is
结果是
True
False
True
False
That is the Spam
class has a property descriptor for eggs
, but since the getter raises AttributeError
if not self.sausages
, then the instance of that class does not "hasattr
" eggs
.
那是Spam
类有一个属性描述符eggs
,但是由于 getter 引发了AttributeError
if not self.sausages
,那么该类的实例不会“ hasattr
” eggs
。
Other than that, use hasattr
only when you don't need the value; if you need the value, use getattr
with 2 arguments and catch the exception, or 3 arguments, the third being a sensible default value.
除此之外,hasattr
仅在您不需要该值时使用;如果您需要该值,请使用getattr
2 个参数并捕获异常,或 3 个参数,第三个是合理的默认值。
The results using getattr()
(2.7.9):
使用getattr()
(2.7.9)的结果:
>>> spam = Spam()
>>> print(getattr(Spam, 'eggs'))
<property object at 0x01E2A570>
>>> print(getattr(spam, 'eggs'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in eggs
AttributeError: No eggs without sausages
>>> spam.sausages = True
>>> print(getattr(spam, 'eggs'))
42
>>> print(getattr(spam, 'invalid'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 10, in invalid
AttributeError: 'Spam' object has no attribute 'invalid'
>>>
回答by hvelarde
Seems that hasattr
has a problem with swallowing exceptions (at least in Python 2.7), so probably is better to stay away from it until it's fixed.
似乎hasattr
吞咽异常有问题(至少在 Python 2.7 中),因此在修复之前最好远离它。
Take, for instance, the following code:
以下面的代码为例:
>>> class Foo(object):
... @property
... def my_attr(self):
... raise ValueError('nope, nope, nope')
...
>>> bar = Foo()
>>> bar.my_attr
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in my_attr
ValueError: nope, nope, nope
>>> hasattr(Foo, 'my_attr')
True
>>> hasattr(bar, 'my_attr')
False
>>> getattr(bar, 'my_attr', None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in my_attr
ValueError: nope, nope, nope
>>>