使用 __set__ 获得 class 级别类型描述符的方法
Way to have a class level type descriptor with __set__
我有数据描述符适用于具有 __set__
和 __get__
的对象。
然而,class 描述符似乎不支持 __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__
如您所见,class 级别 __set__
没有被调用。
是否有一些解决方法或技巧(无论多么可怕)允许 class 上的 __set__
数据描述符?
明确一点,我不希望调用代码必须实现任何 'hack'。我希望调用代码按上面的预期工作,但任何 hack 都是 'behind the scenes'.
使用 Python 2.7
我不会进入整个 Descriptor 协议。我自己并不完全理解;事实上,您已经提醒我,我需要戒掉懒惰,真正 投入其中。同时,我会这样说:
我做的理解是描述符只会在实例上发挥它们的魔力。现在,您可能已经知道这一点,这就是为什么您想知道是否有破解此限制的原因。
如果您稍微熟悉元classes,您就会知道classes 也是实例。 类 可以是 class 的实例,也可以是实例等等。这很好,因为你要问的看起来像这样:
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可见。任何尝试调用它的 Class
实例都会给你一个 AttributeError
。这是因为 classes 的实例,当搜索一个属性时,在搜索 class 的 __dict__
之前先搜索他们自己的 __dict__
,但不会搜索那么远作为 class 的 __metaclass__
。现在,如果你想同时使用它并为 class 及其实例使用相同的变量名(尽管我不推荐它,因为它会引起混淆),你可以这样做:
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()
此时您可能想知道:如果一个实例在搜索它的 class 之前先搜索它自己的 __dict__
,那怎么会调用“Class.descriptor
”如果 Class.descriptor
本质上是它自己的实例变量(来自 metaclass视角)?
答案是数据描述符(同时定义了 __get__
和 __set__
的描述符)与非数据描述符(只定义了 __get__
)不同优先于实例变量。换句话说,MetaClass
中的 descriptor
变量是 Class
将选择的变量,因为它优先于 Class
自己的 descriptor
变量。 Class
实例也是如此,它会自动获取 Class
.
中定义的 descriptor
变量
希望我没有让您感到困惑。这些东西很容易忘记,我认为更是如此,因为大多数时候了解这种魔法水平不是很常见也没有必要。我不得不刷新我对这个的记忆!好问题:)
我有数据描述符适用于具有 __set__
和 __get__
的对象。
然而,class 描述符似乎不支持 __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__
如您所见,class 级别 __set__
没有被调用。
是否有一些解决方法或技巧(无论多么可怕)允许 class 上的 __set__
数据描述符?
明确一点,我不希望调用代码必须实现任何 'hack'。我希望调用代码按上面的预期工作,但任何 hack 都是 'behind the scenes'.
使用 Python 2.7
我不会进入整个 Descriptor 协议。我自己并不完全理解;事实上,您已经提醒我,我需要戒掉懒惰,真正 投入其中。同时,我会这样说:
我做的理解是描述符只会在实例上发挥它们的魔力。现在,您可能已经知道这一点,这就是为什么您想知道是否有破解此限制的原因。
如果您稍微熟悉元classes,您就会知道classes 也是实例。 类 可以是 class 的实例,也可以是实例等等。这很好,因为你要问的看起来像这样:
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可见。任何尝试调用它的 Class
实例都会给你一个 AttributeError
。这是因为 classes 的实例,当搜索一个属性时,在搜索 class 的 __dict__
之前先搜索他们自己的 __dict__
,但不会搜索那么远作为 class 的 __metaclass__
。现在,如果你想同时使用它并为 class 及其实例使用相同的变量名(尽管我不推荐它,因为它会引起混淆),你可以这样做:
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()
此时您可能想知道:如果一个实例在搜索它的 class 之前先搜索它自己的 __dict__
,那怎么会调用“Class.descriptor
”如果 Class.descriptor
本质上是它自己的实例变量(来自 metaclass视角)?
答案是数据描述符(同时定义了 __get__
和 __set__
的描述符)与非数据描述符(只定义了 __get__
)不同优先于实例变量。换句话说,MetaClass
中的 descriptor
变量是 Class
将选择的变量,因为它优先于 Class
自己的 descriptor
变量。 Class
实例也是如此,它会自动获取 Class
.
descriptor
变量
希望我没有让您感到困惑。这些东西很容易忘记,我认为更是如此,因为大多数时候了解这种魔法水平不是很常见也没有必要。我不得不刷新我对这个的记忆!好问题:)