我最近一直在阅读有关hasattr的一些tweetspython 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。

我搜索了hasattrgetattr的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/

10-10 03:29