我有一类对象,其中大多数具有这一属性,在95%的情况下可以将其作为简单属性实现。但是,有一些重要的边缘情况,必须根据另一个对象的数据计算该属性。
我希望能够设置myobj.gnarlyattribute = property(lambda self: self.container.x*self.k)
。
但是,这似乎不起作用:
>>> myfoo=foo()
>>> myfoo.spam
10
>>> import random
>>> myfoo.spam=property(lambda self: random.randint(0,20))
>>> myfoo.spam
<property object at 0x02A57420>
>>>
我想我可以gnarlyattribute
永远是一个通常只有lambda self: self._gnarlyattribute
作为吸气剂的财产,但这似乎有点臭。有什么想法吗?
答案 0 :(得分:1)
正如已经指出的那样,属性只能在类级别工作,并且不能在实例上设置它们。 (好吧,他们可以,但他们不做你想做的事。)
因此,我建议使用类继承来解决您的问题:
class NoProps(object):
def __init__(self, spam=None):
if spam is None:
spam = 0 # Pick a sensible default
self.spam = spam
class Props(NoProps):
@property
def spam(self):
"""Docstring for the spam property"""
return self._spam
@spam.setter
def spam(self, value):
# Do whatever calculations are needed here
import random
self._spam = value + random.randint(0,20)
@spam.deleter
def spam(self):
del self._spam
然后,当您发现某个特定对象需要将其spam
属性作为计算属性时,请将该对象设为Props
而不是NoProps
的实例:
a = NoProps(3)
b = NoProps(4)
c = Props(5)
print a.spam, b.spam, c.spam
# Prints 3, 4, (something between 5 and 25)
如果您可以提前告知您在给定实例中需要计算值,则应该执行您正在寻找的内容。
或者,如果您在创建实例之前无法告诉您需要计算的值,那么这一点也非常简单:只需在您的类中添加一个工厂方法,该方法将复制&#34; old&#34;反对&#34;新&#34;一。例如:
class NoProps(object):
def __init__(self, spam=None):
if spam is None:
spam = 0 # Pick a sensible default
self.spam = spam
@classmethod
def from_other_obj(cls, other_obj):
"""Factory method to copy other_obj's values"""
# The call to cls() is where the "magic" happens
obj = cls()
obj.spam = other_obj.spam
# Copy any other properties here
return obj
class Props(NoProps):
@property
def spam(self):
"""Docstring for the spam property"""
return self._spam
@spam.setter
def spam(self, value):
# Do whatever calculations are needed here
import random
self._spam = value + random.randint(0,20)
@spam.deleter
def spam(self):
del self._spam
因为我们在工厂方法中调用cls()
,所以它将创建一个调用它的类的实例。因此,以下是可能的:
a = NoProps(3)
b = NoProps.from_other_obj(a)
c = NoProps.from_other_obj(b)
print(a.spam, b.spam, c.spam)
# Prints 3, 3, 3
# I just discovered that c.spam should be calculated
# So convert it into a Props object
c = Props.from_other_obj(c)
print(a.spam, b.spam, c.spam)
# Prints 3, 3, (something between 3 and 23)
这两种解决方案中的一种或另一种应该是您正在寻找的。 p>
答案 1 :(得分:0)
The magic to make properties work仅存在于班级。没有办法让属性按对象工作。