Python hasattr 对比 g

2024-06-16 09:38:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我最近读了一些关于hasattr的tweetspython documentation,上面说:

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

在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,而实际上这并不是由于性能的原因?只是因为它更像Python?

也许我在考试中做错了什么:)

谢谢

劳尔


Tags: andofthenameanstringifobject
2条回答

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

例如,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
>>>

文件不鼓励,文件只是说明显而易见的。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'
>>>

相关问题 更多 >