【问题标题】:Pythonic way to only do work first time a variable is called仅在第一次调用变量时才工作的 Pythonic 方式
【发布时间】:2009-10-21 00:51:30
【问题描述】:

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

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

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

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

    age = property(get_age)

谢谢

【问题讨论】:

标签: class variables python precompute


【解决方案1】:
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__ 不会被调用

【讨论】:

  • 如果 attr 不存在,对return getattr(self, attr) 的调用将导致无限循环。请改用return super(MyClass, self).__getattr__(attr)
  • 毫无疑问,如果 attr=='age',getattr 应该返回 self.age,而不是调用 super 的 getattr
  • @~unutbu,super.__getattr__ 在创建后会返回 self.age
  • print(myclass().age) 返回 AttributeError:'super' 对象没有属性 'getattr'。我错过了什么吗?
  • @~unutbu,我也有MyClass 而不是myclass。哎呀。现在已经修复了
【解决方案2】:

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

class myclass(object):

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

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

【讨论】:

  • @nosklo,哎呀,最近做的 C 太多了——已修复,tx
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

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

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

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

      【讨论】:

        猜你喜欢
        • 2016-11-08
        • 2021-06-07
        • 1970-01-01
        • 2017-03-17
        • 2016-02-17
        • 2017-09-19
        • 1970-01-01
        • 2020-09-04
        • 1970-01-01
        相关资源
        最近更新 更多