【问题标题】:How to robustly check a Python property exists?如何稳健地检查 Python 属性是否存在?
【发布时间】:2016-09-15 23:34:14
【问题描述】:

鉴于以下类(具有错误属性),那么检查 bar 属性是否存在的最佳万无一失的方法是什么?

class Foo(object):
    @property
    def bar(self):
        raise AttributeError('unforeseen attribute error!')

hasattrgetattr 都失败了,只有 dir 有效:

foo = Foo()

print hasattr(foo, 'bar')
# False

try:
    getattr(foo, 'bar')
    print True
except AttributeError as e:
    print False
# False    

print 'bar' in dir(foo)
# True

我能想到的最好的全方位解决方案是:

def robust_hasattr(obj, attr):
    return hasattr(obj, attr) or attr in dir(obj)

有没有更好的办法?

【问题讨论】:

  • 为什么需要检查?假设它在那里,如果不存在则处理错误; tryexcept 如果你能从中恢复,或者如果你不能让它传播。
  • 嗯,你的财产确实提高了AttributeError。它坚定地试图表明该属性不存在。您必须检测到这是一个属性的具体用例是什么?
  • 实际用例更复杂——我正在继承一个与硬件对话的类,并且可能有意外的错误(包括属性错误)。在子类中,我只想检查属性名称是否存在(出于接口原因),而不是必须执行它们。 hasattr 的问题在于它通过在潜在复杂的父类中隐藏任何错误(不仅仅是 AttributeError)而“失败”,这使得调试实际错误变得困难。

标签: python properties attributes getattr hasattr


【解决方案1】:

如果您有错误的属性,修复错误。如果提高AttributeError 是一个错误,那么让属性不要这样做。引发该异常是表示您不应该使用该属性的方式。

使用dir() 可能是一种变通方法,但它是not foolproof,因为dir() 是一种调试辅助工具,既可以省略信息,也可以被object.__dir__ 钩子覆盖(为您的代码提供另一个向量引入错误)。然后可能会出现buggy object.__getattr__ hookbuggy object.__getattribute__ hook,甚至是元类上的描述符,所有这些都无法通过使用dir() 检测到。

由于您是专门寻找一个属性,所以在您的对象的类上寻找相同的属性:

hasattr(foo, 'bar') or isinstance(getattr(type(foo), 'bar', None), property)

对于您的具体情况,以上返回 True:

>>> class Foo(object):
...     @property
...     def bar(self):
...         raise AttributeError('unforeseen attribute error!')
...
>>> foo = Foo()
>>> hasattr(foo, 'bar') or isinstance(getattr(type(foo), 'bar', None), property)
True

因为类上确实有这样一个property 对象。

【讨论】:

  • 谢谢,没想到检查类本身。就像我在上面的用例中所说的,我只想检查命名空间而不是执行代码,所以这是一个很好的解决方案。
【解决方案2】:

根据 Python 的规则,bar 属性不存在。如果访问该属性的尝试未引发异常,则认为该对象具有该属性。

如果您想对属性是否存在使用不同的概念,您可以自己实现该概念。例如,要检查实例字典或类字典之一中是否存在与bar 对应的条目:

for obj in (foo,) + type(foo).__mro__:
    if 'bar' in obj.__dict__:
        print "It's there."
        break
else:
    print "Didn't find it."

【讨论】:

  • 为什么不在课堂上使用getattr(),而不是手动走MRO?
  • @MartijnPieters:因为我在考虑其他描述符类型也可能为该类引发 AttributeError。 property 没有必要。
  • @MartijnPieters:但是元类上的描述符不被考虑用于实例上的属性访问,所以我们大多不需要担心它们。不过,我们可能不得不处理__dict____mro__ 的自定义描述符。
  • @Maggyero:如果你想检查一个对象是否是一个数据描述符,你应该跳过实例字典,即使有实例字典。描述符协议会忽略实例字典中的 __set____delete__,就像 Python 内部调用魔术方法的大多数情况一样。
  • 对于覆盖__getattribute__的其他类型,同样可以认为这个答案不起作用。例如,如果您将 super 对象与 super 对象一起使用,它不会执行代理 MRO 搜索 - 另外,正如我们在 2019 年讨论的那样,它假定对象具有实例字典。
猜你喜欢
  • 2022-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-11
  • 1970-01-01
  • 2017-01-15
相关资源
最近更新 更多