【问题标题】:How to know if an object has an attribute in Python如何知道一个对象是否在 Python 中有一个属性
【发布时间】:2010-10-11 06:51:51
【问题描述】:

在 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 属性?

【问题讨论】:

    标签: python attributes


    【解决方案1】:

    试试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 获取示例和简单的解决方法。
    • hasattr 如果您的对象是 'dict' 则不起作用。在这些情况下使用 in operator 或 haskey 方法。
    • 可以为self的属性做吗?比如对象创建的__init__()里面的if not hasattr(self, 'property')
    【解决方案2】:

    正如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

    即:

    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-check 乱扔代码更健壮(程序员更不容易出错)逻辑。使错误也非常明确,并允许使用程序员直接处理它们。
    • 这里的大多数模棱两可的抱怨仅仅是因为示例代码结构不佳。 try: 中唯一的东西应该是尝试的属性访问;也没有理由包装doStuff 的执行。但是仍然存在一些歧义:如果property 是计算属性而不是普通属性,则其实现可能会在内部引发AttributeError。这就是为什么在几乎所有像这样的真实情况下,getattr 都比hasattr 或捕捉AttributeError 更可取。
    【解决方案3】:

    您可以使用hasattr() 或catch AttributeError,但如果您真的只想要具有默认值的属性值(如果它不存在),最好的选择就是使用getattr()

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

    【讨论】:

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

    我认为您正在寻找的是 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-wrapped 函数中引发异常视为不存在此类属性;链接的 Python 邮件列表帖子是关于在您尝试访问它时引发异常的属性。出于所有实际目的,所述属性不存在,因为它永远不会产生值。此外,hasattr 仅在 Py 3.1 及更早版本中抑制一般异常;在 3.2+ 中,它只抑制(替换为 False 返回)AttributeError
    【解决方案5】:

    根据 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 以获得简单的解决方法。
    【解决方案6】:

    我建议避免这种情况:

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

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

    也许这种方法更好:

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

    【讨论】:

      【解决方案7】:

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

      如果您像我一样使用 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)。
      【解决方案8】:

      希望您期待 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() 来代替调用多个方法检查这个@987654321 @
      • 但如果该属性确实存在并且其值为False,您最终可能会误报。
      【解决方案9】:

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

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

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

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

      【讨论】:

        【解决方案10】:

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

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

        【讨论】:

          【解决方案11】:

          对于字典以外的对象:

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

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

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

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

          【讨论】:

            【解决方案12】:

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

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

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

            如另一个answer on SO中所述:

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

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

            【讨论】:

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

            这个超级简单,用dir(object)
            这将返回对象的每个可用函数和属性的列表。

            【讨论】:

              【解决方案14】:

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

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

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

              方法签名本身是hasattr(object, name) -&gt; bool,这意味着如果object具有属性,它被传递给hasattr中的第二个参数,而不是根据TrueFalse给出布尔值对象中存在name 属性。

              【讨论】:

              • nit: hasattr() 是一个函数,而不是一个方法。 See here.
              【解决方案15】:

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-09-29
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多