是否有可能用“普通”属性替换对象的属性?
我需要这个,因为当我访问属性的第一个,我想要的属性生成的值。 但之后我不再需要财产:
class A(object): @property def x(self): self.x = "toto" # Replace property, fail because no setter return self.x a = A() print a.x # "toto" a.x = "tata"我知道我可以将值存储在_x等第二个属性中,并检查属性是否存在_x ,但是我想知道是否有可能替换属性本身。
Is it possible to replace a property of an object with 'normal' attribute?
I need this because when I access the attribute for the first, I want the value to be generated by the property. But I no longer need the property afterward:
class A(object): @property def x(self): self.x = "toto" # Replace property, fail because no setter return self.x a = A() print a.x # "toto" a.x = "tata"I know I can store the value in a second attribute like _xand check in the property if _x exist but I want to know if it's possible the replace the property itself.
最满意答案
为了避免缺少setter,你必须直接操作实例__dict__字典。 然而,你不能用常规的property对象来做你想做的事情,因为它是一个数据描述符 。 属性访问将始终为实例属性提供数据描述符优先级。
您必须创建一个自定义描述符,而不是定义__set__或__delete__方法:
class CachingProperty(object): def __init__(self, fget): self.name = fget.__name__ self.fget = fget def __get__(self, instance, owner): if instance is None: return self value = self.fget(instance) instance.__dict__[self.name] = value return value该描述符还负责直接在实例__dict__属性中设置值,从而创建一个实例属性。
使用上面的类而不是property :
class A(object): @CachingProperty def x(self): return "toto"演示,显示getter方法只被调用一次:
>>> class Demo(object): ... @CachingProperty ... def foo(self): ... print("Calling the foo property") ... return "bar" ... >>> d = Demo() >>> d.foo Calling the foo property 'bar' >>> d.foo 'bar' >>> vars(d) {'foo': 'bar'}To bypass the lack of a setter, you'd have to directly manipulate the instance __dict__ dictionary. However, you can't do what you want with a regular property object, because it is a data descriptor. Attribute access will always give a data descriptor priority over instance attributes.
You'd have to create a custom descriptor instead, one that doesn't define a __set__ or __delete__ method:
class CachingProperty(object): def __init__(self, fget): self.name = fget.__name__ self.fget = fget def __get__(self, instance, owner): if instance is None: return self value = self.fget(instance) instance.__dict__[self.name] = value return valueThis descriptor also takes care of setting the value directly in the instance __dict__ attribute, thus creating an instance attribute.
Use the above class instead of property:
class A(object): @CachingProperty def x(self): return "toto"Demo, showing that the getter method is only called once:
>>> class Demo(object): ... @CachingProperty ... def foo(self): ... print("Calling the foo property") ... return "bar" ... >>> d = Demo() >>> d.foo Calling the foo property 'bar' >>> d.foo 'bar' >>> vars(d) {'foo': 'bar'}更多推荐
发布评论