我想要一个具有属性class MyClass(object):
@property
def attr(self):
try:
return self._cached_result
except AttributeError:
result = ...
self._cached_result = result
return result
obj = MyClass()
print obj.attr # First calculation
print obj.attr # Cached result is used
的类,当第一次访问时,它会运行一个函数并返回一个值,然后变为这个值(它的类型)变化等。)。
可以通过以下方式获得类似的行为:
.attr
但是,执行此操作时,obj.attr
如果它确实会更有效率。
难点在于将obj.attr
设置为属性后,无法轻松将其设置为其他内容,因为无限循环会自然出现。因此,在上面的代码中,obj.attr
属性没有setter,因此无法直接修改。如果定义了setter,则替换此setter中的self.attr = …
会创建一个无限循环(从setter中访问setter)。我还想到了第一次删除 setter,以便能够使用del self.attr
进行常规self.attr
,但这会调用属性删除器(如果有的话),这会重新创建无限循环问题(obj.attr
的修改通常倾向于通过属性规则。)
那么,有没有办法绕过属性机制并用MyClass.attr.__getter__
内的任何内容替换绑定属性 std::string B(std::string& data)
{
messaging::BMessage* msg = new messaging::BMessage;
msg->ParseFromString(data); // here didn't work probably coz this function takes string (with string* data is address)
return msg->data();
}
?
答案 0 :(得分:3)
这看起来有点像过早优化:您希望通过使描述符自身更改来跳过方法调用。
这完全可能,但必须证明是合理的。
要修改属性中的描述符,您必须编辑您的类,这可能不是您想要的。
我认为实现这一目标的更好方法是:
obj.attr
__getattr__
,如果参数为" attr",obj.attr = new_value
,否则引发AttributeError
一旦obj.attr
被设置,__getattr__
将不再被调用,因为它仅在属性不存在时被调用。 (__getattribute__
是一直被调用的那个。)
与您的初始提案的主要区别在于,由于__getattr__
的方法调用开销,第一个属性访问速度较慢,但它将与常规__dict__
查找一样。< / p>
示例:
class MyClass(object):
def __getattr__(self, name):
if name == 'attr':
self.attr = ...
return self.attr
raise AttributeError(name)
obj = MyClass()
print obj.attr # First calculation
print obj.attr # Cached result is used
编辑:请参阅the other answer,特别是如果您使用的是Python 3.6或更高版本。
答案 1 :(得分:1)
对于使用描述符协议的新式类,您可以通过创建自己的自定义描述符类来完成此操作,其中__get__()
方法最多只能调用一次。当发生这种情况时,然后通过创建类方法具有相同名称的实例属性来缓存结果。
这就是我的意思。
from __future__ import print_function
class cached_property(object):
"""Descriptor class for making class methods lazily-evaluated and caches the result."""
def __init__(self, func):
self.func = func
def __get__(self, inst, cls):
if inst is None:
return self
else:
value = self.func(inst)
setattr(inst, self.func.__name__, value)
return value
class MyClass(object):
@cached_property
def attr(self):
print('doing long calculation...', end='')
result = 42
return result
obj = MyClass()
print(obj.attr) # -> doing long calculation...42
print(obj.attr) # -> 42