我最近一直在阅读有关hasattr的一些tweets和python documentation,它说:
Python中有一个座右铭,即(通常我同意),它比许可更容易寻求宽恕。
在这种情况下,我尝试使用一个非常简单的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)
结果如下:
$ python test.py
hasattr(a, 'a')
1.26515984535
getattr(a, 'a')
1.32518696785
我还尝试了如果该属性不存在并且getattr和hasattr之间的差异较大时会发生什么情况。因此,到目前为止,我所看到的是getattr的速度比hasattr慢,但是在文档中说它叫做getattr。
我搜索了hasattr和getattr的CPython实现,似乎两者都调用了下一个函数:
v = PyObject_GetAttr(v, name);
但是getattr中的样板比hasattr中的样板更多,这可能会使它变慢。
有谁知道为什么在文档中我们说hasattr称为getattr,并且我们似乎鼓励用户在实际上不是由于性能而使用getattr而不是hasattr?仅仅是因为它更具有pythonic功能?
也许我在测试中做错了:)
谢谢,
劳尔
最佳答案
文档不鼓励使用,文档只说明了显而易见的内容。 hasattr
是这样实现的,并且从属性getter抛出AttributeError
可使它看起来好像该属性不存在。这是一个重要的细节,这就是为什么在文档中明确说明了它的原因。例如考虑以下代码:
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'))
结果是
True
False
True
False
那是
Spam
类具有eggs
的属性描述符,但是由于getter如果将AttributeError
引发为not self.sausages
,则该类的实例不将hasattr
设置为eggs
。除此之外,仅当不需要值时才使用
hasattr
;如果需要该值,请使用带有2个参数的getattr
并捕获该异常或3个参数,第三个是明智的默认值。使用
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'
>>>
关于Python hasattr与getattr,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24971061/