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

Reb*_*ebs 4 python methods descriptor python-2.7

我有数据描述符适用于具有__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
Run Code Online (Sandbox Code Playgroud)

哪个输出

Object
__get__
__set__
Class
__get__
Run Code Online (Sandbox Code Playgroud)

如您所见,类级别__set__没有被调用.

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

为了清楚起见,我不希望调用代码来实现任何"黑客".我希望调用代码按照预期的方式工作,但任何黑客都是"幕后".

使用Python 2.7

Eit*_*hos 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...
Run Code Online (Sandbox Code Playgroud)

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()
Run Code Online (Sandbox Code Playgroud)

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

答案是数据描述符(具有__get____set__定义的描述符)与非数据描述符(仅定义的__get__)相比,优先于实例变量.换句话说,该descriptor变量MetaClass是一个Class将回升,因为它的优先级高于Class自己的descriptor变量.这同样适用于所述Class的实例,它可以自动拾取descriptor中定义的变量Class.

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