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


1630

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之前,如何判断该属性是否具有?

Answers:


2334

尝试hasattr()

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

编辑:请参阅下面的zweiterlinde的答案,他为寻求宽恕提供了很好的建议!一个非常pythonic的方法!

python中的一般做法是,如果大多数情况下该属性可能都存在,则只需对其进行调用并允许该异常传播,或者使用try / except块捕获该属性。这可能会比快hasattr。如果该属性在大多数时间可能不存在,或者您不确定,则使用该属性可能hasattr比重复陷入异常块要快。


19
似乎也正在检查名称空间中的函数,例如: import string hasattr(string, "lower")
riviera

15
hasattr与使用try/ 完全相同except AttributeError:hasattr的文档字符串(在python 2.7中)说它使用getattr手捕获异常。
杰夫·特拉纳

8
@JeffTratner:hasattr不幸的try: ... except AttributeError:Python 2.x 并不完全相同,因为hasattr它将捕获所有exception。请查看我的答案以获取示例和简单的解决方法。
Martin Geisler 2013年

1
@MartinGeisler好点-它与捕获所有异常不同。不确定哪个版本更正确-确实取决于您正在使用的假设以及谁在调用您的函数。感谢您的澄清。
杰夫·特拉纳

2
hasattr如果您有理解力,它也是一个不错的选择,例如[a.property for a in list_of_as if hasattr(a, "property")]
Rafael Martins '18

631

正如Jarret Hardie回答的那样,hasattr将完成此操作。不过,我想补充一点,Python社区中的许多人都建议一种策略:“更容易要求宽恕而不是许可”(EAFP),而不是“三思而后行”(LBYL)。请参阅以下参考:

EAFP vs. LBYL(当时:到目前为止有点失望)
EAFP vs. LBYL @Code像Python一样:惯用的Python

即:

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

...优先于:

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

257
但是,如何检查是导致AttributeError的a.property,而不是doStuff()中的某物?看来你没有。我认为请求宽恕真的很容易,但是很多时候,这也是不正确的。
jpalecek

282
EAFP似乎……发疯了。HasAttr向正在检查特定属性的将来的维护程序员发送电报。遇到异常不会告诉未来的程序员任何事情,并且可能导致某人陷入困境。
伊桑·海尔曼

74
@ e5:在这种情况下,您有一个公平的观点,但是在许多情况下,EAFP是唯一正确的选择。例如,如果您检查文件是否存在,然后打开它,并期望它肯定存在,则您的代码不正确:在检查和使用之间可能会删除或重命名该文件。这称为TOCTOU错误(使用时间检查),除了引起崩溃之外,还可能是安全漏洞的来源。
最多

15
@EthanHeilman只有在异常源中存在歧义的情况下,这才是疯狂的事情,在大多数情况下,可以通过良好的设计来避免这种情况。在try / except / final中,分层的逻辑结构通常比使用每条消耗代码的if-check抢先的代码散布代码更健壮(程序员更不会出错)。使错误也非常明确,并允许消耗程序员选择直接处理它们的选项。
彼得·埃里亚斯

64
这里大多数含混不清的抱怨仅仅是因为示例代码的结构不良。里面唯一的东西try:应该是尝试的属性访问。也没有理由也要包装执行doStuff。但是,仍然存在一些歧义的可能性:如果property是计算属性而不是普通属性,则其实现可能会在AttributeError内部引发。这就是为什么在几乎所有这样的真实情况下getattr都比hasattr或都更可取的原因AttributeError
卡尔·梅耶

483

您可以使用hasattr()或catch AttributeError,但是如果您确实只想使用带有缺省值的属性值(如果该值不存在),最好的选择就是使用getattr()

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

14
这解决了上述两个问题:a)可能的AttributeError的来源不明确,b)保留EAFP方法。
彼得·埃里亚斯

6
它也是代码行的25%。当然,这必须是最好的解决方案。
fatuhoku

16
这是最好的解决方案,“如果您确实只想使用默认值作为属性的值”。尽管我相信这是许多人说要检测是否存在某个属性时真正想要的,但OP实际上要求使用后者,因此将该问题的直接答案(hasattr,AttributeError)列出较高是合理的。
卡尔·梅耶

41

我认为您正在寻找的是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


因此,您的建议是您不要内置-实施它!
SilentGhost

好吧,不完全是,不要使用您要检测属性的内置IFF。否则,hasattr非常好。
batbrat

3
hasattr通常检测属性就可以了。只是将property-wrapped函数中的引发异常视为不存在此类属性;链接的Python邮件列表帖子是关于一个属性的,当您尝试访问它时会引发异常。出于所有实际目的,所述属性不存在,因为它永远不会产生值。而且,hasattr仅抑制Py 3.1及更早版本的异常。在3.2+中,它仅抑制(用Falsereturn 代替)AttributeError
ShadowRanger

32

根据pydoc的说法,hasattr(obj,prop)仅调用getattr(obj,prop)并捕获异常。因此,用try语句包装属性访问并捕获AttributeError就像预先使用hasattr()一样有效。

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

2
好哈萨特实际上可以被优化。例如与pypy。
奥迪尼奥-费尔蒙

6
+1。这比使用when 重写更为安全hasattr,因为它将捕获Python 2.x中的所有异常,而不仅仅是您期望的那样。这已在Python 3.2中修复-请参阅我的其他答案以获取一个简单的解决方法。SomeClass__getattr__hasattrAttributeError
Martin Geisler 2013年

24

我建议避免这种情况:

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

用户@jpalecek提到了它:如果在AttributeError内部发生doStuff(),那么您会迷路。

也许这种方法更好:

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

也可能只是:try: a.property不需要左手
Petruza

然后,您必须在else块中重复a.property,否则可能会失败。
埃里克·阿劳霍

13

您可以根据情况检查所拥有isinstance的对象类型,然后使用相应的属性。随着Python 2.6 / 3.0 中抽象基类的引入,这种方法也变得更加强大(基本上,ABC允许使用更复杂的鸭子输入方式)。

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

一个很好的例子是迭代器和可迭代器之间的区别(请参阅问题)。__iter__迭代器和可迭代的方法的名称相同,但语义上却大不相同!因此hasattr是没有用的,但是isinstance与ABC一起提供了一个干净的解决方案。

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


13

希望您期望使用hasattr(),但要避免使用hasattr(),请优先使用getattr()。getattr()比hasattr()更快

使用hasattr():

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

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

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

11

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

如果您像我一样使用Python 3.6或更高版本,可以使用一种方便的替代方法来检查对象是否具有特定的属性:

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

但是,我不确定哪种方法是目前最好的方法。使用hasattr(),使用getattr()或使用in。欢迎发表评论。


6
in关键字可用于检查可迭代类型。例如,'foo' in None抛出错误TypeError: argument of type 'NoneType' is not iterable。解决方法是在使用之前检查类型是否可迭代in。在纠正了诸如不可迭代类型之类的边缘情况之后,您最好使用hasattr()它,因为它是为处理边缘情况而设计的。
塞斯·迪夫利

3
这与属性访问无关。我不知道它是如何得到支持的。它唯一具有属性访问权限的相似性是如果您dict用作“轻量级对象”,类似于JavaScript对象的设计,但大多数普通类通常不会支持此操作(获取@SethDifley提到的错误的变体) 。
ShadowRanger

2
如果类中的变量是__dict__:?


1

您可以object使用hasattr内置方法检查是否包含属性。

对于实例,如果您的对象是a并且您要检查属性stuff

>>> class a:
...     stuff = "something"
... 
>>> hasattr(a,'stuff')
True
>>> hasattr(a,'other_stuff')
False

方法签名本身是hasattr(object, name) -> bool指是否object具有传递给第二个参数的属性hasattr然后给出布尔值TrueFalse根据name对象中属性的存在。



1

另一个可能的选择,但这取决于您之前的意思:

undefined = object()

class Widget:

    def __init__(self):
        self.bar = 1

    def zoom(self):
        print("zoom!")

a = Widget()

bar = getattr(a, "bar", undefined)
if bar is not undefined:
    print("bar:%s" % (bar))

foo = getattr(a, "foo", undefined)
if foo is not undefined:
    print("foo:%s" % (foo))

zoom = getattr(a, "zoom", undefined)
if zoom is not undefined:
    zoom()

输出:

bar:1
zoom!

这使您甚至可以检查无值属性。

但!要非常小心,不要意外实例化并比较undefined多个位置,因为is在这种情况下,将永远无法工作。

更新:

由于我在上一段中警告过,具有多个从未匹配的未定义,因此我最近对这种模式进行了一些修改:

undefined = NotImplemented

NotImplemented,不要与混淆NotImplementedError,它是内置的:它半匹配JS的意图,undefined您可以在任何地方重用它的定义,并且它将始终匹配。缺点是,它在布尔值中是“真实的”,并且在日志和堆栈跟踪中看起来很奇怪(但是当您知道它仅在此上下文中出现时,您会很快克服它)。


0

hasattr()是正确的答案。我要补充的是,hasattr()它还可以与assert一起很好地使用(以避免不必要的if语句并使代码更具可读性):

assert hasattr(a, 'property'), 'object lacks property' 

关于SO的另一个答案中所述:应该使用断言来测试永远不会发生的条件。目的是在程序状态损坏的情况下尽早崩溃。


这是有帮助的,但并非总是如此。也许我想测试对象是否具有属性,然后第一次添加它,或者也许我必须为具有该属性的对象运行不同的代码。当代码无法继续时,断言可能很好。但是,并非总是如此。重要的是hasattr不要使用周围的代码。
Lucas GabrielSánchez
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.