Динамическое добавление @property в python
Я знаю, что я могу динамически добавлять метод экземпляра к объекту, делая что-то вроде:
import types
def my_method(self):
# logic of method
# ...
# instance is some instance of some class
instance.my_method = types.MethodType(my_method, instance)
Позже я могу позвонить instance.my_method()
, а self будет правильно привязан и все будет работать.
Теперь, мой вопрос: как сделать то же самое, чтобы получить поведение, которое украшало бы новый метод с помощью @property?
Я бы предположил что-то вроде:
instance.my_method = types.MethodType(my_method, instance)
instance.my_method = property(instance.my_method)
Но при этом instance.my_method
возвращает объект свойства.
Ответы
Ответ 1
Объекты дескриптора property
должны находиться в классе, а не в экземпляре, чтобы иметь желаемый эффект. Если вы не хотите изменять существующий класс, чтобы не изменять поведение других экземпляров, вам нужно создать "класс для каждого экземпляра", например:
def addprop(inst, name, method):
cls = type(inst)
if not cls.hasattr('__perinstance'):
cls = type(cls.__name__, (cls,), {})
cls.__perinstance = True
setattr(cls, name, property(method))
Я отмечаю эти специальные классы "каждый экземпляр" атрибутом, чтобы избежать ненужного создания нескольких, если вы выполняете несколько вызовов addprop
в одном экземпляре.
Обратите внимание, что, как и для других видов использования property
, вам нужен класс в игре новый стиль (обычно полученный путем наследования прямо или косвенно из object
), а не древний стиль устаревшего (опущен в Python 3), который по умолчанию присваивается классу без баз.
Ответ 2
Поскольку этот вопрос не задает вопрос о добавлении только к экземпляру spesific,
следующий способ может быть использован для добавления свойства к классу, это будет подвергать свойства всем экземплярам класса YMMV.
cls = type(my_instance)
cls.my_prop = property(lambda self: "hello world")
print(my_instance.my_prop)
# >>> hello world
Примечание: добавление другого ответа, потому что я думаю, что @Alex Martelli, верный, добивается желаемого результата, добавляя метод обертки, мой ответ должен быть более прямым/прямым, без абстрагирования того, что происходит в его собственном методе.