Почему набор дескрипторов Python не вызывается


У меня есть дескриптор класса, и его метод __set__ не вызывается. Я долго и упорно искал это в течение нескольких часов, и у меня нет ответа на этот вопрос. Но то, что я заметил ниже, это то, что когда я назначаю 12 своему тесту.X, он стирает дескриптор свойства для X и заменяет его значением 12. Поэтому вызывается оператор print для функции Get. Это хорошо.

Но оператор print для функции __set__ вообще не вызывается. Неужели я пропал? что-нибудь?

class _static_property(object):
    ''' Descriptor class used for declaring computed properties that don't require a class instance. '''
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter

    def __get__(self, instance, owner):
        print "In the Get function"
        return self.getter.__get__(owner)()

    def __set__(self, instance, value):
        print "In setter function"
        self.setter.__get__()(value)

class MyTest(object):
    _x = 42

    @staticmethod
    def getX():
        return MyTest._x

    @staticmethod
    def setX(v):
        MyTest._x = v

    X = _static_property(getX, setX)


print MyTest.__dict__
print MyTest.X
MyTest.X = 12
print MyTest.X
print MyTest.__dict__
3   5   2013-08-08 22:49:57

3 ответа:

Два других ответа указывают на использование метаклассов для выполнения того, что вы хотите сделать. Чтобы помочь узнать о них, вот пример применения одного из них к коду в вашем вопросе, который заставляет его делать то, что вы хотите:

class _static_property(object):
    """Descriptor class used for declaring computed properties that
       don't require a class instance.
    """
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter

    def __get__(self, obj, objtype=None):
        print("In the getter function")
        return self.getter(obj)

    def __set__(self, obj, value):
        print("In setter function")
        self.setter(obj, value)

class _MyMetaClass(type):
    def getX(self):
        return self._x

    def setX(self, v):
        self._x = v

    X = _static_property(getX, setX)

class MyTest(object):
    __metaclass__ = _MyMetaClass  # Python 2 syntax
    _x = 42

#class MyTest(object, metaclass=_MyMetaClass):  # Python 3 (only) syntax
#    _x = 42

print(MyTest.__dict__)
print(MyTest.X)
MyTest.X = 12
print(MyTest.X)
print(MyTest.__dict__)
Классы-это экземпляры их метакласса, который обычно имеет тип type. Однако вы можете использовать его в качестве базового класса и создать свой собственный специализированный мета-подкласс , который в данном случае имеет атрибуты класса, являющиеся дескрипторами данных (он же свойства). Обратите внимание, что аргумент self в методе meta или meta-subclass является экземпляром метакласса, который является классом. В приведенном выше коде он называется MyTest.

Дескрипторы работают с экземплярами классов, а не с самими классами. Если бы у вас был пример MyTest, X будет работать, как вы ожидаете, но доступ к нему в качестве атрибута класса фактически устанавливает атрибут самого объекта класса. Вы можете попробовать определить пользовательский метакласс для добавления дескриптора, а затем создать MyTest с этим метаклассом.

__set__ вызывается только при назначении X экземпляра

Если вы хотите, чтобы это работало для класса attibute, вам придется настроить дескриптор в метаклассе MyTest