Python 懒惰属性在 hasattr() 时不求值

6 投票
6 回答
1951 浏览
提问于 2025-04-15 13:38

有没有办法做一个装饰器,让属性变得懒加载,也就是说在你用 hasattr() 检查属性的时候,它不会提前计算?我已经弄明白怎么让它懒加载了,但用 hasattr() 的时候,它会提前计算。比如:

class lazyattribute:
    # Magic.

class A:
    @lazyattribute
    def bar(self):
      print("Computing")
      return 5

>>> a = A()
>>> print(a.bar)
'Computing'
5
>>> print(a.bar)
5
>>> b = A()
>>> hasattr(b, 'bar') 
'Computing'
5
# Wanted output: 5

6 个回答

0

问题在于,hasattr 这个函数会使用 getattr,所以每次你用 hasattr 检查属性时,那个属性都会被计算一次。如果你能把你的 lazyattribute 的代码发出来,希望有人能建议一种不需要用到 hasattrgetattr 的方法来检查属性是否存在。可以查看 hasattr 的帮助文档了解更多信息:

>>> help(hasattr)
Help on built-in function hasattr in module __builtin__:

hasattr(...)
    hasattr(object, name) -> bool

    Return whether the object has an attribute with the given name.
    (This is done by calling getattr(object, name) and catching exceptions.)
3

到目前为止,似乎没有人提到过,或许最好的做法是不要使用 hasattr()。相反,可以采用EAFP的方式(即“请求原谅比请求许可更简单”)。

try:
    x = foo.bar
except AttributeError:
    # what went in your else-block
    ...
else:
    # what went in your if hasattr(foo, "bar") block
    ...

显然,这并不是一个直接可以替换的方案,你可能需要稍微调整一下代码,但这可能是最“好”的解决办法(当然,这是个人观点)。

4

这可能有点难。根据hasattr 的文档

hasattr(object, name)

这个函数需要两个参数,一个是对象,另一个是字符串。结果如果字符串是这个对象的某个属性的名字,就返回 True;如果不是,就返回 False。(这个过程是通过调用 getattr(object, name) 来实现的,然后看看是否会出现异常。)

因为属性可能是通过 __getattr__ 方法动态生成的,所以没有其他可靠的方法来检查它们是否存在。对于你的特殊情况,可能直接检查字典就足够了:

any('bar' in d for d in (b.__dict__, b.__class__.__dict__))

撰写回答