使用__set__获得类级别类型描述符的方法

时间:2015-02-09 04:58:55

标签: python python-2.7 methods descriptor

我的数据描述符适用于__set____get__的对象。

但是,类描述符似乎不支持__set__。这样做会用描述的值替换描述符对象本身。

以下代码演示了此

from __future__ import print_function

class Descriptor(object):
    def __get__(self, obj, cls):
        print('__get__')
    def __set__(self, obj, value):
        print('__set__')

class Class(object):
    descriptor = Descriptor()

print('Object')
a = Class()
a.descriptor
a.descriptor = 1

print('Class')
Class.descriptor
Class.descriptor = 2

哪个输出

Object
__get__
__set__
Class
__get__

如您所见,班级__set__未被调用。

是否有允许在类上使用__set__数据描述符的解决方法或黑客(无论多么可怕)?

为了清楚起见,我不希望调用代码来实现任何' hack'。我希望调用代码能够按照预期的方式工作,但任何黑客都要在幕后进行操作'。

使用Python 2.7

1 个答案:

答案 0 :(得分:5)

我不会涉及整个描述符协议。我不自己完全理解;事实上,你提醒我,我需要放弃懒惰,真的潜入它。同时,我会这样说:

的理解是描述符只会在实例上发挥作用。现在,你可能已经知道了这一点,这就是为什么你想知道是否有一个黑客可以绕过这个限制。

如果您对元类有一点熟悉,您就会知道类也是实例。类可以是类的实例,也可以是实例等等。这很好,因为你问的东西会是这样的:

class Descriptor(object):
    def __get__(self, obj, cls):
        print('__get__')
    def __set__(self, obj, value):
        print('__set__')

class MetaClass(type):
    descriptor = Descriptor()

class Class(object):
    __metaclass__ = MetaClass

# This will work fine when you do Class.descriptor, as you asked
# but it will raise an AttributeError if you do 
# a = Class()
# a.descriptor
# Read on for the full explanation...

descriptor中定义的MetaClass变量仅对Class类可见。试图调用它的Class的任何实例都会为您提供AttributeError。这是因为类的实例在搜索属性时会在搜索类的__dict__之前搜索自己的__dict__,但它不会搜索类的__metaclass__。现在,如果你想同时使用它并为类及其实例使用相同的变量名(虽然我不推荐它,因为它会引起混淆),你可以这样做:

class Descriptor(object):
    def __get__(self, obj, cls):
        print('__get__')
    def __set__(self, obj, value):
        print('__set__')

class MetaClass(type):
    descriptor = Descriptor()

class Class(object):
    __metaclass__ = MetaClass
    descriptor = Descriptor()

此时您可能想知道:如果实例在搜索其类之前搜索其自己的__dict__,那么调用“Class.descriptor”如何不会选择相同的描述符如果a.descriptor本质上是它自己的实例变量(来自元类POV),“Class.descriptor”使用(正如您所观察到的那样,它将无法正常工作)?

答案是数据描述符(定义了__get____set__的描述符),而不是非数据描述符(仅定义__get__),优先于实例变量。换句话说,descriptor中的MetaClass变量是Class将要选择的变量,因为它优先于Class自己的descriptor变量。 Class实例也是如此,该实例会自动选择descriptor中定义的Class变量。

我希望我没有让你困惑。这个东西很容易忘记,我认为是双倍的,因为在大多数情况下理解这种魔法并不是很常见也不必要。我必须在这一个上恢复我的记忆!好问题:)