【问题标题】:Way to have a class level type descriptor with __set__使用 __set__ 获得类级别类型描述符的方法
【发布时间】:2015-02-09 04:58:54
【问题描述】:

我的数据描述符适用于具有__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”。我希望调用代码按上述预期工作,但任何 hack 都在“幕后”。

使用 Python 2.7

【问题讨论】:

    标签: python python-2.7 methods descriptor


    【解决方案1】:

    我不会进入整个描述符协议。我自己不完全理解;事实上,你已经提醒我,我需要放弃懒惰并真正投入其中。同时,我会这样说:

    的理解是描述符只会在实例上发挥它们的魔力。现在,您可能已经知道这一点,这就是为什么您想知道是否有破解此限制的方法。

    如果您对元类稍有了解,就会知道类也是实例。类可以是类的实例,也可以是实例等。这很好,因为您要问的内容看起来像这样:

    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...
    

    MetaClass 中定义的descriptor 变量仅对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相同的描述符' 如果Class.descriptor 本质上是它自己的实例变量(来自元类 POV),则使用(正如您所观察到的那样,它不能正常工作)

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

    希望我没有让你感到困惑。这些东西很容易忘记,我认为是双重原因,因为大多数时候理解这种级别的魔法并不常见,也没有必要。我不得不刷新我对这个的记忆!好问题:)

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多