ChatGPT解决这个技术问题 Extra ChatGPT

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

如何确定对象是否具有某些属性?例如:

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

在使用之前如何判断 a 是否具有属性 property

当您说“在使用之前判断a 是否具有attribute 属性?” 您希望函数返回布尔值(如hasattr() 返回)还是可以抛出AttributeError 异常?
此外,实际上不要将您的属性命名为 'property' ,因为 Python 也有 property decorator and builtin,而且它们与普通属性/方法略有不同。

N
Neuron

试试 hasattr()

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

请参阅下面的 zweiterlinde's answer,谁提供了关于请求宽恕的好建议!一个非常pythonic的方法!

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


似乎也在检查命名空间中的函数,例如:import string hasattr(string, "lower")
hasattr 与使用 try/except AttributeError 完全相同:hasattr 的文档字符串(在 Python 2.7 中)表示它使用 getattr 手动捕获异常。
@JeffTratner:很遗憾,hasattr 与 Python 2.x 中的 try: ... except AttributeError: 并不完全相同,因为 hasattr捕获所有异常。有关示例和简单的解决方法,请参阅 my answer
如果您的对象是“dict”,则 hasattr 不起作用。在这些情况下使用 operator 或 haskey 方法。
可以为 self 的属性完成吗?像对象创建的 __init__() 内的 if not hasattr(self, 'property')
G
Gfy

正如 Jarret Hardie 回答的那样,hasattr 可以解决问题。不过,我想补充一点,Python 社区中的许多人建议采用“更容易请求宽恕而不是许可”(EAFP)而不是“在跳跃之前先看”(LBYL)的策略。请参阅这些参考资料:

EAFP vs LBYL (was Re: A little disappointed so far)
EAFP vs. LBYL @Code Like a Pythonista: Idiomatic Python

IE:

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

...首选:

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

但是如何检查导致 AttributeError 的是 a.property,而不是 doStuff() 中的某个东西?看来你没有。我认为请求原谅真的很容易,但很多时候,它也是不正确的。
EAFP 似乎……疯了。 HasAttr 向未来的维护程序员电报您正在检查特定属性。获得异常不会告诉未来的程序员任何事情,并且可能会导致某人陷入困境。
@e5:在这种情况下你有一个公平的观点,但在许多情况下 EAFP 是唯一正确的选择。例如,如果您检查文件是否存在,然后打开它,期望它肯定存在,那么您的代码是错误的:文件可能在检查和使用之间被删除或重命名。这称为 TOCTOU 错误(Time-Of-Check-To-Time-Of-Use),除了导致崩溃之外,还可能是安全漏洞的来源。
@EthanHeilman 只有在异常来源有歧义时才会发疯,在大多数情况下,通过良好的设计可以避免这种情况。 try / except / finally 中的分层逻辑结构通常比使用对每段消费代码的抢先式 if 检查乱扔代码更健壮(程序员更不容易出错)逻辑。使错误也非常明确,并允许使用程序员直接处理它们。
这里的大多数模棱两可的抱怨仅仅是因为示例代码的结构很差。 try: 内的唯一内容应该是尝试的属性访问;也没有理由包装 doStuff 的执行。但仍有一些歧义的可能性:如果 property 是计算属性而不是普通属性,则其实现可能会在内部引发 AttributeError。这就是为什么在几乎所有像这样的实际情况下,getattr 都比 hasattr 或捕获 AttributeError 更可取。
G
Georgy

您可以使用 hasattr() 或 catch AttributeError,但如果您真的只希望该属性的值没有默认值,那么最好的选择就是使用 getattr()

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

这解决了上述两个问题:a)可能的 AttributeError 来源的模糊性,b)保留 EAFP 方法。
它也是代码行数的 25%。当然,这必须是最好的解决方案。
这是最好的解决方案,“如果您真的只希望属性的值具有默认值”。虽然我相信这是许多人说他们想要检测属性是否存在时真正想要的,但 OP 实际上要求后者,因此将该问题的直接答案(hasattr,AttributeError)列在更高的位置是合理的.
赞成提到“默认属性”。有几次我需要这个,但忘记了!
b
batbrat

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


hasattr 通常可以很好地检测属性。只是它将在 property 包装的函数中引发异常视为不存在此类属性;链接的 Python 邮件列表帖子是关于在您尝试访问它时引发异常的属性。出于所有实际目的,所述属性不存在,因为它永远不会产生值。此外,hasattr 仅在 Py 3.1 及更早版本中抑制一般异常;在 3.2+ 中,它只抑制(替换为 False 返回)AttributeError
J
Jordan Lewis

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

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

那么 hasattr 实际上可能会被优化。例如与 pypy。
+1。当 SomeClass 覆盖 __getattr__ 时,这甚至比使用 hasattr更安全,因为 hasattr 将捕获 Python 2.x 中的所有异常,而不仅仅是 AttributeError就像你期望的那样。这已在 Python 3.2 中修复 — 请参阅 my other answer 了解简单的解决方法。
M
Maico

我想建议避免这种情况:

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

用户 @jpalecek 提到它:如果 AttributeError 出现在 doStuff() 中,你就迷路了。

也许这种方法更好:

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

n
nayak

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

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

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

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


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

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

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

如果缺少该属性,程序将退出并显示 AssertionError 并打印出提供的错误消息(在本例中为 object lacks property)。

如另一个 answer on SO 所述:

断言应该用于测试不应该发生的情况。目的是在程序状态损坏的情况下尽早崩溃。

这通常是缺少某个属性然后 assert 非常合适的情况。


这很有帮助,但可能并非总是如此。也许我想测试对象是否具有属性,然后第一次添加它,或者我必须为具有该属性的对象运行不同的代码。当代码无法继续时,断言可能会很好。但同样,情况并非总是如此。重要的是使用 hasattr 而不是周围的代码。
C
Community

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

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

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

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


J
Janarthanan Ramu

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

使用 hasattr():

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

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

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

getattr() is faster than hasattr(),您能对此发表评论吗?为什么更快?
@Groosha 有很多事情,为了简单起见,hasattr() 内部必须调用 getattr() 来执行它们的操作,所以我们可以直接使用 getattr() 检查这个docs.python.org/3/library/functions.html#hasattr,而不是调用多个方法
但是,如果该属性确实存在并且其值为 False,则您最终可能会误报。
N
Neuron

对于字典以外的对象:

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

对于字典,hasattr() 不起作用。

许多人告诉使用 has_key() 作为字典,但它已被贬值。所以对于字典,你必须使用 has_attr()

if a.has_attr('property'):
    a['property']
 

对于 dict,使用 if 'property' in a:
A
Alec

这是一个非常直观的方法:

if 'property' in dir(a):
    a.property

S
Sean Christians

这非常简单,只需使用 dir(object)
这将返回对象的每个可用函数和属性的列表。


D
Devang Padhiyar

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

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

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

方法签名本身是 hasattr(object, name) -> bool,这意味着如果 object 具有传递给 hasattr 中的第二个参数的 attribute,则它会根据 True 的存在给出布尔值 TrueFalse 6} 对象中的属性。


nit: hasattr() 是一个函数,而不是一个方法。 See here.
J
JL Peyret

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

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 的意图,您可以在任何地方重用它的定义,它总是匹配的。缺点是它在布尔值中是“真实的”,并且在日志和堆栈跟踪中看起来很奇怪(但是当你知道它只出现在这个上下文中时你很快就会克服它)。