Python 在运行时重写@property getter
有没有办法在Python的运行时重写@property getter 我希望我的类有一个“复杂”的getter,它运行一些代码并返回一个可以更改的值。但是,如果出于某种原因,我将该变量设置为其他变量,我希望它始终返回该值 例如:Python 在运行时重写@property getter,python,properties,overriding,Python,Properties,Overriding,有没有办法在Python的运行时重写@property getter 我希望我的类有一个“复杂”的getter,它运行一些代码并返回一个可以更改的值。但是,如果出于某种原因,我将该变量设置为其他变量,我希望它始终返回该值 例如: class Random(object): @property def random_number(): return random.randint(0,10) @random_number.setter def ra
class Random(object):
@property
def random_number():
return random.randint(0,10)
@random_number.setter
def random_number(value):
# Overlord says that random must always return `value`
(((I don't know that to do here)))
>>>r = Random()
>>>r.random_number
>>>(returns something between 0,10)
>>>r.random_number = 4 # Confirmed by dice roll
>>>r.random_number
>>>4 (always)
我知道我可以使用“force_value”这样的实例变量来解决这个问题,我总是在getter中签入它,但如果可能的话,我希望避免这样做
理想情况下,我的setter函数可以执行以下操作
self.random_number.getter = lambda:4
但是我不知道如何使它工作。您不能在实例级别“重写”属性,因为属性是一个同时具有“get”和“set”钩子的属性 这意味着您的getter必须检查实例属性。这并不像听起来那么痛苦:
class Random(object):
@property
def random_number(self):
if hasattr(self, '_override'):
return self._override
return random.randint(0,10)
@random_number.setter
def random_number(self, value):
# Overlord says that random must always return `value`
self._override = value
您甚至可以添加删除程序:
@random_number.deleter
def random_number(self):
if hasattr(self, '_override'):
del self._override
另一种方法是创建您自己的替代描述符类,该类不实现_setter__挂钩,因此您可以直接在实例上设置属性并让它重写描述符。但是对于您的用例来说,仅仅使用显式setter似乎更简单。您可以编写自己的类似属性的类,但不需要使用uuu set\uuu-方法。这样,设置属性将创建实例属性,而不是调用setter方法
import random
class property_getter(object):
def __init__(self, getter):
self.getter = getter
def __get__(self, obj, cls):
return self.getter(obj)
class Random(object):
@property_getter
def random_number(self):
return random.randint(0,10)
x = Random()
print x.random_number
print x.random_number
x.random_number = 5
print x.random_number
可以在运行时替换属性。实际上,即使是定义属性并将其附加到类的行为也是一个运行时操作,在Python中,在运行时之前没有发生任何值得注意的事情。但是,由于属性是描述符,并且描述符是类的一部分,因此它不是存储每个实例数据的正确位置。您仍然应该使用一个单独的变量,可能是self.\u number,如果您真的必须实现这种愚蠢且令人困惑的行为,则表示还没有强制执行任何变量。您可以将数字的源定义为一个使用属性设置器切换的函数。这是因为Python支持运动,这意味着您可以在不调用它们的情况下获取对它们的引用,并像其他任何对象一样传递它们:
from functools import partial
import random
class Random(object):
def __init__(self):
self.number_source = partial(random.randint, 0, 10)
@property
def random_number(self):
return self.number_source()
@random_number.setter
def random_number(self, value):
self.number_source = lambda: value
r = Random()
print r.random_number
r.random_number = 42
print r.random_number
输出:
<random int>
42
有关partialrandom.randint,0,10的详细信息,请参阅文档。它基本上创建了一个函数,调用时调用random.randint0,10并返回结果 那很聪明。我只是不确定聪明在这里是否是件好事。这正是我想要做的,所以我把它标记为被接受。但是,我同意其他人的看法,我将坚持使用简单且不太神奇的覆盖实例属性。