python: 属性字段是否自动缓存?

37 投票
8 回答
18494 浏览
提问于 2025-04-16 20:00

我的问题是,下面这两段代码在解释器运行时是否是一样的:

class A(object):
  def __init__(self):
     self.__x = None

  @property
  def x(self):
     if not self.__x:
        self.__x = ... #some complicated action
     return self.__x

还有更简单的:

class A(object):
  @property
  def x(self):
      return ... #some complicated action

也就是说,解释器是否足够聪明,可以记住属性 x 的值?

我的假设是 x 的值不会改变 - 找到它是很“麻烦”的,但一旦找到一次,就没有理由再去找第二次。

8 个回答

19

不,你需要添加一个叫做 memoize 的装饰器:

class memoized(object):
   """Decorator that caches a function's return value each time it is called.
   If called later with the same arguments, the cached value is returned, and
   not re-evaluated.
   """
   def __init__(self, func):
      self.func = func
      self.cache = {}
   def __call__(self, *args):
      try:
         return self.cache[args]
      except KeyError:
         value = self.func(*args)
         self.cache[args] = value
         return value
      except TypeError:
         # uncachable -- for instance, passing a list as an argument.
         # Better to not cache than to blow up entirely.
         return self.func(*args)
   def __repr__(self):
      """Return the function's docstring."""
      return self.func.__doc__
   def __get__(self, obj, objtype):
      """Support instance methods."""
      return functools.partial(self.__call__, obj)

@memoized
def fibonacci(n):
   "Return the nth fibonacci number."
   if n in (0, 1):
      return n
   return fibonacci(n-1) + fibonacci(n-2)

print fibonacci(12)
24

如果你在2020年看到这个内容,想告诉你,这个功能现在在Python 3.8的标准库中可以通过functools模块使用了。

https://docs.python.org/dev/library/functools.html#functools.cached_property

需要注意的是,定义了自己__dict__(或者根本没有定义)或者使用__slots__的类,可能不会按预期工作。比如,NamedTuple和元类(metaclasses)就是这样的例子。

36

不,获取器(getter)每次你访问这个属性时都会被调用。

撰写回答