6

是否可以制作一个使属性变得惰性的装饰器,当您尝试使用它访问它时不会评估它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
4

5 回答 5

4

这可能很难做到。从hasattr 文档中:

hasattr(对象,名称)

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

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

any('bar' in d for d in (b.__dict__, b.__class__.__dict__))
于 2009-08-17T07:40:27.147 回答
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
    ...

这显然不是直接替代品,您可能需要稍微移动一下,但这可能是“最好的”解决方案(当然,主观上)。

于 2009-08-18T03:21:54.793 回答
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.)
于 2009-08-17T07:37:25.970 回答
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
于 2009-08-18T04:16:43.190 回答
-2

好吧,修复有点骇人听闻,但它包括以下内容

  1. 重命名 hasattr(比如 _hasattr)
  2. 重新绑定 hasattr 如下:


   def hasattr(obj, name):
     try:
       return obj._hasattr(name) or _hasattr(obj, name)
     except:
       return _hasattr(obj, name)

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

  2. 最后以某种方式让您的 @lazyattribute 装饰器将项目添加到某种结构中(例如我们上面提到的数组),然后当您调用 _hasattr 然后您查看该结构

    • 这是我不太确定您将如何实现的步骤,因为我还没有创建自己的装饰器
于 2009-08-17T08:04:15.977 回答