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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 05:32:40  来源:igfitidea点击:

Python hasattr vs getattr

pythonpython-2.7python-3.xcpython

提问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:

我搜索了hasattrgetattr的 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 hasattris implemented as such, and throwing an AttributeErrorfrom 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 Spamclass has a property descriptor for eggs, but since the getter raises AttributeErrorif not self.sausages, then the instance of that class does not "hasattr" eggs.

那是Spam类有一个属性描述符eggs,但是由于 getter 引发了AttributeErrorif not self.sausages,那么该类的实例不会“ hasattreggs

Other than that, use hasattronly when you don't need the value; if you need the value, use getattrwith 2 arguments and catch the exception, or 3 arguments, the third being a sensible default value.

除此之外,hasattr仅在您不需要该值时使用;如果您需要该值,请使用getattr2 个参数并捕获异常,或 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 hasattrhas 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
>>>