Python 懒惰属性在 hasattr() 时不求值
有没有办法做一个装饰器,让属性变得懒加载,也就是说在你用 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
的代码发出来,希望有人能建议一种不需要用到 hasattr
或 getattr
的方法来检查属性是否存在。可以查看 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__))