[英]Pythonic way to only do work first time a variable is called
my Python class has some variables that require work to calculate the first time they are called.我的 Python 类有一些变量需要在第一次调用它们时进行计算。 Subsequent calls should just return the precomputed value.
后续调用应该只返回预先计算的值。
I don't want to waste time doing this work unless they are actually needed by the user.我不想浪费时间做这项工作,除非用户确实需要它们。 So is there a clean Pythonic way to implement this use case?
那么有没有一种干净的 Pythonic 方式来实现这个用例?
My initial thought was to use property() to call a function the first time and then override the variable:我最初的想法是第一次使用 property() 调用函数,然后覆盖变量:
class myclass(object):
def get_age(self):
self.age = 21 # raise an AttributeError here
return self.age
age = property(get_age)
Thanks谢谢
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 mentioned you can use __getattr__
, this is how it works亚历克斯提到你可以使用
__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__()
is invoked when the attribute doesn't exist on the object, ie. __getattr__()
在对象上不存在属性时调用,即。 the first time you try to access age
.第一次尝试访问
age
。 Every time after, age
exists so __getattr__
doesn't get called每次之后,
age
存在,所以__getattr__
不会被调用
property
, as you've seen, will not let you override it.正如您所见,
property
不会让您覆盖它。 You need to use a slightly different approach, such as:您需要使用稍微不同的方法,例如:
class myclass(object):
@property
def age(self):
if not hasattr(self, '_age'):
self._age = self._big_long_computation()
return self._age
There are other approaches, such as __getattr__
or a custom descriptor class, but this one is simpler!-)还有其他方法,例如
__getattr__
或自定义描述符类,但这种方法更简单!-)
Here is decorator from Python Cookbook for this problem: 这是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
Yes you can use properties, though lazy evaluation is also often accomplished using descriptors, see eg:是的,您可以使用属性,但通常也使用描述符来完成惰性求值,例如:
http://blog.pythonisito.com/2008/08/lazy-descriptors.html http://blog.pythonisito.com/2008/08/lazy-descriptors.html
This question is already 11 years old, and python 3.8 and above now come with cached_property , which perfectly serves this purpose.这个问题已经有 11 年的历史了,python 3.8 及更高版本现在带有cached_property ,它完美地满足了这个目的。 The property will be computed only once, then kept in memory for subsequent use.
该属性将只计算一次,然后保存在内存中以供后续使用。
Here is how to use it in this case:在这种情况下如何使用它:
class myclass(object):
@cached_property
def age(self):
return 21 #This can be a long computation
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.