如何更换/绕过类属性?

时间:2016-08-01 10:44:03

标签: python properties attributes

我想要一个具有属性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(); }

2 个答案:

答案 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