繁体   English   中英

Python hasattr vs getattr

[英]Python hasattr vs getattr

我最近一直在阅读一些关于hasattr的推文python文档 ,它说:

hasattr(对象,名称)

参数是一个对象和一个字符串。 如果字符串是>>对象属性之一的名称,则结果为True,否则返回False。 (这是通过调用getattr(object,name)并查看它是否引发AttributeError来实现的。)

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 ,那么该类的实例不会“ hasattreggs

除此之外,只有在不需要值时才使用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'
>>>

似乎hasattr有吞咽异常的问题(至少在Python 2.7中 ),所以最好远离它直到它被修复。

例如, 以下代码

>>> 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
>>>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM