在hasattr()上没有eval的Python延迟属性

时间:2009-08-17 07:15:59

标签: python decorator lazy-evaluation

当您尝试使用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

5 个答案:

答案 0 :(得分:4)

可能很难做到。来自hasattr documentation

hasattr(对象,名称)

参数是一个对象和一个字符串。如果字符串是对象属性之一的名称,则结果为True,否则返回False。 (这是通过调用getattr(object,name)并查看它是否引发异常来实现的。

由于属性可能由__getattr__方法动态生成,因此没有其他方法可靠地检查它们的存在。对于您的特殊情况,也许明确地测试字典就足够了:

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

答案 1 :(得分:2)

到目前为止,没有人似乎已经解决过,或许最好的办法就是不要使用hasattr()。相反,去EAFP(更容易请求宽恕而不是许可)。

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

这显然不是替代品,你可能需要稍微调整一下,但它可能是“最好的”解决方案(主观上,当然)。

答案 2 :(得分: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 :(得分:0)

我很好奇为什么你需要这样的东西。如果hasattr最终调用您的“计算功能”,那么就这样吧。你的财产究竟需要多么懒惰?

但是,通过检查调用函数的名称,这是一种相当不切实际的方法。它可能编码得更好一些,但我认为它不应该被认真使用。

import inspect

class lazyattribute(object):
    def __init__(self, func):
        self.func = func

    def __get__(self, obj, kls=None):
        if obj is None or inspect.stack()[1][4][0].startswith('hasattr'):
            return None
        value = self.func(obj)
        setattr(obj, self.func.__name__, value)
        return value

class Foo(object):
    @lazyattribute
    def bar(self):
        return 42

答案 4 :(得分:-2)

好的修复有点hackish但它包含以下

  1. 重命名hasattr(比如_hasattr)
  2. 重新绑定hasattr如下:
  3. 
       def hasattr(obj, name):
         try:
           return obj._hasattr(name) or _hasattr(obj, name)
         except:
           return _hasattr(obj, name)
    

    1. 通过检查一些填充了所有惰性属性名称的数据结构(即数组)来实现类方法_hasattr(对于你要说的数组:name in lazyAttrArray)

    2. 最后以某种方式让你的@lazyattribute装饰器将项添加到某种结构中(比如我们上面提到的数组),然后当你调用_hasattr时,你会看到那个结构

      • 这是我不太确定你如何实施的步骤因为我没有创建自己的装饰