python描述符的状态在哪里?

Fin*_*inn 7 python

背景

我试图通过阅读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结尾?

Eth*_*man 2

“与属性一样,描述符被设计为处理特定的属性...与属性不同,描述符有自己的状态...”

我不确定 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)