我的数据描述符适用于__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
答案 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
变量。
我希望我没有让你困惑。这个东西很容易忘记,我认为是双倍的,因为在大多数情况下理解这种魔法并不是很常见也不必要。我必须在这一个上恢复我的记忆!好问题:)