题 如何知道对象在Python中是否具有属性


有没有办法在Python中确定对象是否具有某些属性?例如:

>>> a = SomeClass()
>>> a.someProperty = value
>>> a.property
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: SomeClass instance has no attribute 'property'

你怎么知道 a 有属性 property 在使用之前?


1143
2018-03-04 14:45


起源




答案:


尝试 hasattr()

if hasattr(a, 'property'):
    a.property

编辑:见 zweiterlinde的回答 下面,谁提供了关于请求宽恕的好建议!一种非常pythonic的方法!

python中的一般做法是,如果属性可能在大多数时间都存在,只需调用它并让异常传播,或者使用try / except块捕获它。这可能会比 hasattr。如果财产很可能在大多数时间不存在,或者你不确定,使用 hasattr 可能会比反复陷入异常块更快。


1599
2018-03-04 14:48



似乎也在检查命名空间中的函数,例如: import string hasattr(string, "lower") - riviera
hasattr 与使用完全相同 try/except AttributeError:hasattr的docstring(在Python 2.7中)说它使用getattr hand catches exception。 - Jeff Tratner
我认为最明显的用例与宽恕无关,如果懒惰初始化则“初始化它”。初始化和在源中使用的共址通常比在一个地方初始化和在另一个地方使用更好。 - Evgeni Sergeev
@JeffTratner: hasattr 遗憾的是没有 究竟 和a一样 try: ... except AttributeError: 在Python 2.x中 hasattr 将 抓住所有例外。请参见 我的答案 一个例子和一个简单的解决方法。 - Martin Geisler
@MartinGeisler好点 - 它捕获所有异常并不相同。不确定哪个版本更正确 - 实际上取决于您正在使用的假设以及谁正在调用您的函数。谢谢你的澄清。 - Jeff Tratner


Jarret Hardie 回答: hasattr 会做的伎俩。不过,我想补充一点,Python社区中的许多人都建议采用“更容易请求宽恕而不是许可”(EAFP)的策略,而不是“在你跳跃之前先看”(LBYL)。见这些参考文献:

EAFP对LBYL(Re:到目前为止有点失望)
EAFP与LBYL @Code像Pythonista:惯用语

即:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

...优先:

if hasattr(a, 'property'):
    doStuff(a.property)
else:
    otherStuff()

463
2018-03-04 14:56



但是你怎么检查它是导致AttributeError的a.property,而不是doStuff()中的东西?看来你没有。我认为要求宽恕真的很容易,但很多时候,这也是不正确的。 - jpalecek
EAFP似乎......疯了。 HasAttr致电未来的维护程序员,您正在检查特定属性。获得一个例外可以告诉未来的程序员什 - Ethan Heilman
@ e5:在这种情况下你有一个公平的观点,但在很多情况下,EAFP是唯一正确的选择。例如,如果检查文件的存在然后打开它,期望它肯定存在,则代码不正确:文件可能会在检查和使用之间被删除或重命名。这称为TOCTOU错误(使用时间检查时间),除了导致崩溃之外,还可能是安全漏洞的来源。 - Max
@EthanHeilman当异常来源存在歧义时,它才会疯狂,在大多数情况下可以通过良好的设计来避免。在try / except / finally中良好分层的逻辑结构通常比使用对每条消费代码进行抢占式if-check乱丢代码更有效(更少程序员容易出错)逻辑。使错误也非常明确,并允许程序员直接处理它们。 - Peter M. Elias
这里的大多数含糊不清的投诉仅仅是因为示例代码结构不合理。里面唯一的东西 try: 应该是尝试的属性访问;没有理由包装执行 doStuff 同样。尽管如此,仍然存在一些模棱两可的可能性: property 是一个计算属性而不是普通属性,它的实现可能会提高 AttributeError 内部。这就是为什么在几乎所有这样的真实情况下, getattr 优于任何一个 hasattr 或捕捉 AttributeError。 - Carl Meyer


您可以使用 hasattr() 或抓住 AttributeError,但如果你真的只想要属性的值,如果它不存在,那么最好的选择就是使用 getattr()

getattr(a, 'property', 'default value')

371
2018-03-04 17:54



这解决了上述两个问题:a)可能的AttributeError源的模糊性,b)保留EAFP方法。 - Peter M. Elias
它也是25%的代码行。当然,这必须是最好的解决方案。 - fatuhoku
这是最好的解决方案“如果你真的只想要属性值的默认值。”虽然我相信这是许多人在说他们想要检测属性是否存在时实际想要的,但OP实际上要求后者,所以将该问题的直接答案(hasattr,AttributeError)列为更高是合理的。 - Carl Meyer
但 hynek.me/articles/hasattr - AlxVallejo


我想你要找的是 hasattr。但是,如果你想检测,我会推荐这样的东西 python属性 -

try:
    getattr(someObject, 'someProperty')         
except AttributeError:
    print "Doesn't exist"
else
    print "Exists"

这里的缺点是属性中的属性错误 __get__ 代码也被捕获。

否则,做 -

if hasattr(someObject, 'someProp'):
    #Access someProp/ set someProp
    pass

文档:http://docs.python.org/library/functions.html
警告:
我推荐的原因是hasattr没有检测到属性。
链接:http://mail.python.org/pipermail/python-dev/2005-December/058498.html


33
2018-03-04 14:52



所以,你的建议是不要你积累 - 实施它! - SilentGhost
嗯,不完全是,不要使用你想要检测属性的内置IFF。否则hasattr非常好。 - batbrat
hasattr 检测属性一般就好了。只是它在对待提出例外 property - 包含函数,意思是不存在这样的属性;链接的Python邮件列表帖子是关于在您尝试访问它时引发异常的属性。出于所有实际目的,所述属性不存在,因为它永远不会产生值。也, hasattr 只抑制Py 3.1及更早版本的异常;在3.2+中,它只能抑制(替换为 False 返回) AttributeError。 - ShadowRanger


根据pydoc,hasattr(obj,prop)只需调用getattr(obj,prop)并捕获异常。因此,使用try语句包装属性访问并捕获AttributeError同样有效,因为它是事先使用hasattr()。

a = SomeClass()
try:
    return a.fake_prop
except AttributeError:
    return default_value

24
2018-03-04 14:56



实际上好吧 也许 优化。例如。与pypy。 - odinho - Velmont
+1。这是偶数 更安全 而不是使用 hasattr 什么时候 SomeClass 覆盖 __getattr__ 以来 hasattr 会抓住 所有 Python 2.x中的异常,而不仅仅是 AttributeError 就像你期望的那样。这是在Python 3.2中修复的 - 请参阅 我的另一个答案 一个简单的解决方法。 - Martin Geisler


我想建议避免这个:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

用户@jpalecek提到它:如果是 AttributeError 发生在里面 doStuff(), 你迷路了。

也许这种方法更好:

try:
    val = a.property
except AttributeError:
    otherStuff()
else:
    doStuff(val)

13
2017-08-26 13:04





根据具体情况,您可以查看 isinstance 你有什么样的对象,然后使用相应的属性。随着介绍 抽象基类 在Python 2.6 / 3.0中,这种方法也变得更加强大(基本上ABCs允许更复杂的鸭子打字方式)。

一种情况是,如果两个不同的对象具有相同名称但具有不同含义的属性,则这是有用的。仅使用 hasattr 然后可能会导致奇怪的错误。

一个很好的例子是迭代器和迭代器之间的区别(参见 这个 题)。该 __iter__ 迭代器和迭代中的方法具有相同的名称,但在语义上完全不同!所以 hasattr 没用,但是 isinstance 与ABC一起提供了一个干净的解决方案。

但是,我同意在大多数情况下 hasattr 方法(在其他答案中描述)是最合适的解决方案。


11
2018-03-04 15:41





编辑:这种方法有严重的局限性。如果对象是一个,它应该工作 迭代 一。请查看以下评论​​。

如果你正在使用 Python 3.6 或像我这样的更高级别的方法可以检查对象是否具有特定属性:

if 'attr1' in obj1:
    print("attr1 = {}".format(obj1["attr1"]))

但是,我不确定现在哪种方法最好。运用 hasattr(),使用 getattr() 或使用 in。欢迎评论。


9
2018-06-22 06:32



in 关键字适用于检查可迭代类型。例如, 'foo' in None 抛出错误 TypeError: argument of type 'NoneType' is not iterable。修复是在使用之前检查类型是否可迭代 in。在纠正非可迭代类型等边缘情况后,您可能最好使用 hasattr() 因为它的设计是为了处理边缘情况。 - Seth Difley
这与属性访问无关。我不知道它是如何被投票的。它与属性访问的唯一相似之处在于您是否正在使用 dict 作为一个“轻量级对象”,类似于JavaScript对象的设计,但大多数普通类通常不支持这种情况(获取@SethDifley提到的错误的变体)。 - ShadowRanger


希望你期待hasattr(),但尽量避免使用hasattr(),请更喜欢getattr()。 getattr()比hasattr()更快

使用hasattr():

 if hasattr(a, 'property'):
     print a.property

同样在这里我使用getattr来获取属性,如果没有属性则返回none

   property = getattr(a,"property",None)
    if property:
        print property

7
2017-12-30 07:49