我试图通过阅读Lutz的学习Python的部分来解决Python的描述符,其中他说:"像属性一样,描述符旨在处理特定的属性......与属性不同,描述符有自己的状态......"
在本章中,他展示了托管属性实际隐藏在包含/包装对象上的示例,如:
def __set__(self, instance, value):
instance._name = value.lower()
Run Code Online (Sandbox Code Playgroud)
我理解这些例子,它们似乎在关于该主题的写作中很常见.也就是说,他们对财产的好处对我来说并不明显,他们似乎没有达到上述报价所承诺的内部状态.
在本章的最后,他展示了一个更接近我所描绘的"拥有自己的状态"的例子,如:
def __set__(self, instance, value):
self.name = value.lower()
Run Code Online (Sandbox Code Playgroud)
该示例运行但不执行我期望它执行的操作.由于示例有点长,我把它放在Pastebin上并添加了显示意外行为的最后一行(Bob的名字现在是Sue).这是一个较短的演示片段:
class Wrapper(object):
class ExampleDescriptor(object):
def __get__(self, instance, owner):
print "get %s" % self.state
return self.state
def __set__(self, instance, value):
print "set %s" % value
self.state = value
ex = ExampleDescriptor()
w1 = Wrapper()
w1.ex = 1
print w1.ex
w2 = Wrapper()
print w2.ex
w2.ex = 2
print w1.ex
print w1.ex is w2.ex
Run Code Online (Sandbox Code Playgroud)
其输出是:
set 1
get 1
1
get 1
1
set 2
get 2
2
get 2
get 2
True
Run Code Online (Sandbox Code Playgroud)
在仔细查看代码之后,这些执行都没有出乎意料.描述符中的验证逻辑是在包装类的这个属性中制作事实上的单例; 然而,这是很难想象这种共享状态是卢茨的意图,或打算在这个广联教程的话题.
是否有可能创建一个具有包装对象唯一的内部状态的描述符,而不会在包装对象实例上存储该状态(如第一个代码段中那样)?是否可以CardHolder从链接的示例中修改类,以便Bob不会以Sue结尾?
“与属性一样,描述符被设计为处理特定的属性...与属性不同,描述符有自己的状态...”
我不确定 Lutz 想要表达什么观点,因为属性实际上就是描述符本身。
但是,即使描述符确实有自己的状态,它也没有广泛用处,因为正如您所发现的,每个类属性只能获得一个描述符对象,而不是每个实例一个。这就是传入实例的原因,以便可以保存/访问实例唯一的值。
为了证明每个属性都是一个描述符对象,您可以从您的链接之一尝试这个稍微修改过的代码:
class RevealAccess(object):
"""A data descriptor that sets and returns values
normally and prints a message logging their access.
"""
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print 'Retrieving', self.name
return self.val
def __set__(self, obj, val):
print 'Updating' , self.name
self.val = val
class MyClass(object):
x = RevealAccess(10, 'var "x"')
y = RevealAccess(5, 'var "y"')
m = MyClass()
m.x
m.x = 20
m.x
m.y
Run Code Online (Sandbox Code Playgroud)
你应该看到什么:
Retrieving var "x"
Updating var "x"
Retrieving var "x"
Retrieving var "y"
Run Code Online (Sandbox Code Playgroud)
回答你的问题:是的。但这很痛苦。
class Stored(object):
"""A data descriptor that stores instance values in itself.
"""
instances = dict()
def __init__(self, val):
self.instances[self, None] = val
def __get__(self, obj, objtype):
return self.instances[self, obj]
def __set__(self, obj, val):
self.instances[self, obj] = val
class MyClass(object):
x = Stored(3)
y = Stored(9)
print(MyClass.x)
print(MyClass.y)
m = MyClass()
m.x = 42
print(m.x)
m.y = 19
print(m.y)
print(m.x)
Run Code Online (Sandbox Code Playgroud)