为什么不调用Python描述符__set__

时间:2013-08-08 18:49:57

标签: python

我在类上有一个描述符,并且不会调用它的__set__方法。我一直在寻找这个问题几个小时并且没有答案。但是我在下面注意到的是,当我将12分配给MyTest.X时,它会擦除​​X的属性描述符,并将其替换为值12.因此调用Get函数的print语句。那很好。

__set__函数的print语句根本不会被调用。我错过了什么吗?

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 个答案:

答案 0 :(得分:5)

另外两个答案提到使用元类来完成你想要做的事情。为了帮助我们了解它们,这里有一个例子,它将一个应用到您问题中的代码中,使其按照您的意愿执行:

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参数是元类实例,它是一个类。在上面的代码中,它的名称为MyTest

答案 1 :(得分:4)

描述符可以处理类的实例,而不是类本身。如果您有MyTest的实例,X将按预期工作,但作为类属性访问它实际上设置了类对象本身的属性。您可以尝试定义自定义元类以添加描述符,然后使用该元类创建MyTest

答案 2 :(得分:3)

__set__仅在您分配给实例的X时被调用

如果您希望这适用于类属性,则必须在MyTest

的元类上设置描述符