7

我的 Python 类有一些变量需要在第一次调用时进行计算。后续调用应该只返回预先计算的值。

除非用户确实需要它们,否则我不想浪费时间做这项工作。那么有没有一种干净的 Pythonic 方式来实现这个用例呢?

我最初的想法是第一次使用 property() 调用一个函数,然后覆盖变量:

class myclass(object):
    def get_age(self):
        self.age = 21 # raise an AttributeError here
        return self.age

    age = property(get_age)

谢谢

4

5 回答 5

14
class myclass(object):
    def __init__(self):
        self.__age=None
    @property
    def age(self):
        if self.__age is None:
            self.__age=21  #This can be a long computation
        return self.__age

亚历克斯提到你可以使用__getattr__,这就是它的工作原理

class myclass(object):
    def __getattr__(self, attr):
        if attr=="age":
            self.age=21   #This can be a long computation
        return super(myclass, self).__getattribute__(attr)

__getattr__()当对象上不存在该属性时调用,即。第一次尝试访问age。每次之后,age都存在所以__getattr__不会被调用

于 2009-10-21T01:01:54.863 回答
6

property,如您所见,不会让您覆盖它。您需要使用稍微不同的方法,例如:

class myclass(object):

    @property
    def age(self):
      if not hasattr(self, '_age'):
        self._age = self._big_long_computation()
      return self._age

还有其他方法,例如__getattr__自定义描述符类,但这个更简单!-)

于 2009-10-21T01:04:03.470 回答
4

Python Cookbook中针对此问题的装饰器:

class CachedAttribute(object):
    ''' Computes attribute value and caches it in the instance. '''
    def __init__(self, method, name=None):
        # record the unbound-method and the name
        self.method = method
        self.name = name or method.__name__
    def __get__(self, inst, cls):
        if inst is None:
            # instance attribute accessed on class, return self
            return self
        # compute, cache and return the instance's attribute value
        result = self.method(inst)
        setattr(inst, self.name, result)
        return result
于 2009-10-21T09:05:04.997 回答
2

是的,您可以使用属性,尽管延迟评估也经常使用描述符来完成,例如:

http://blog.pythonisito.com/2008/08/lazy-descriptors.html

于 2009-10-21T01:02:05.723 回答
1

这个问题已经有 11 年的历史了,python 3.8 及更高版本现在带有cached_property,它完美地服务于这个目的。该属性将只计算一次,然后保存在内存中以供后续使用。

以下是在这种情况下如何使用它:

class myclass(object):
    @cached_property
    def age(self):
        return 21  #This can be a long computation
于 2021-06-24T06:59:02.050 回答