Pythonic方式只能在第一次调用变量时才能工作

时间:2009-10-21 00:51:31

标签: class variables python precompute

我的Python类有一些变量,需要工作来计算第一次调用它们。后续调用应该只返回预先计算的值。

除非用户实际需要,否则我不想浪费时间做这项工作。 那么有一个干净的Pythonic方法来实现这个用例吗?

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

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

    age = property(get_age)

由于

5 个答案:

答案 0 :(得分:13)

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

Alex提到你可以使用__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__不会被调用

答案 1 :(得分:6)

正如您所见,

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

class myclass(object):

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

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

答案 2 :(得分:4)

Here是来自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

答案 3 :(得分:2)

是的,你可以使用属性,虽然懒惰的评估也经常使用描述符完成,参见例如:

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

答案 4 :(得分:0)

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

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

class myclass(object):
    @cached_property
    def age(self):
        return 21  #This can be a long computation