Функция создателя свойства

1

Я хотел бы иметь функцию в объекте, который создает элемент определенного поведения. Аналогично использованию декоратора @property. Но без объявления функции getter и setter. Я хотел бы создать много членов пользовательского поведения с теми же функциями getter и setter. Однако этот пример не работает. Когда я его new_prop член new_prop является объектом свойства, а не членом. Как я могу достичь своей цели?

class MyClass():
    def __init__(self):
        self.new_prop("my_prop1")
        self.new_prop("my_prop2")
        self.new_prop("my_prop3")

    def new_prop(self, name):
        def getter(self):
            this_prop = getattr(self, "_" + name)
            if this_prop is None:
                return "This is None!"
            else:
                return this_prop
        def setter(self, value):
            setattr(self, "_" + name, value)
        setattr(self, name, property(getter, setter))
        setattr(self, "_" + name, None)

if __name__ == "__main__":
    my_class = MyClass()

    print(type(my_class.my_prop1))
Теги:
properties

2 ответа

3
Лучший ответ

property является дескриптором, и, как и все дескрипторы, он вызывается только при разрешении как атрибут класса - как вы обнаружили, когда он является атрибутом экземпляра, методы __get__ и __set__ не вызываются.

Если ваша цель состоит в том, чтобы избежать переписывания одних и тех же геттеров и сеттеров для свойств N, простым простым решением является написать собственный дескриптор:

class MyProp(object):
    def __init__(self, name):
        self.name = name

    def __get__(self, obj, cls):
        if obj is None:
            return self
        value = getattr(obj, "_" + self.name)
        if value is None:
           return "This is None!"
        else:
           return value

    def __set__(self, obj, value):
        setattr(obj, "_" + self.name, value)


class Foo(object):
    prop1 = MyProp("prop1")
    prop2 = MyProp("prop2")
  • 0
    Есть ли способ использовать ваше решение так, чтобы мне не нужно было писать «prop1 = MyProp (« prop1 »)», а вместо этого что-то вроде: «add_prop (« prop1 »)»
  • 1
    Нет, или, по крайней мере, без какого-то очень неприятного взлома, и даже тогда ... Это связано с тем, как работает оператор class и как создаются объекты класса - в основном оператор class выполняет все операторы на верхнем уровне блок class , собирает все имена, созданные в этом блоке, в dict, передает этот dict в type() и связывает полученный объект класса с именем класса во вложенном пространстве имен. Это означает, что класс еще не существует при выполнении prop1 = MyProp(...) , поэтому MyProp не может получить к нему доступ.
Показать ещё 2 комментария
1

Обратите внимание, что свойство объявляется как атрибут класса. Поэтому вы должны установить его в классе, а не в экземпляре:

setattr(self.__class__, name, property(getter, setter))

Является ли это полезным, это еще один вопрос, особенно установка атрибута класса в __init__ для каждого экземпляра. Вам следует рассмотреть возможность внедрения собственного дескриптора вне класса, чтобы вы могли:

class MyClass():
     my_prop1 = new_prop("my_prop1")
     my_prop2 = new_prop("my_prop2")
     my_prop3 = new_prop("my_prop3")

Ещё вопросы

Сообщество Overcoder
Наверх
Меню