python - python 描述符的状态去哪里了?

标签 python

背景

我想弄清楚 Python's descriptors通过阅读 Lutz 的 Learning Python's section on the topic他在其中说:“与属性一样,描述符旨在处理特定属性……与属性不同,描述符具有自己的状态……”

在本章中,他展示了一些示例,其中托管属性实际上隐藏在包含/包装对象上,如:

def __set__(self, instance, value):
    instance._name = value.lower()

我理解这些例子,它们似乎在 write ups 中很常见关于这个话题。也就是说,他们的利益超过了 properties对我来说并不明显,它们似乎没有达到上述引用中 promise 的内部状态。

在本章的末尾,他展示了一个更接近我在阅读“拥有自己的状态”后所描绘的例子,如:

def __set__(self, instance, value):
    self.name = value.lower()

该示例运行但未执行我期望的操作。作为the example有点长我把它放在 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

其输出为:

set 1 
get 1
1
get 1
1
set 2
get 2
2
get 2
get 2
True

仔细查看代码后,这种执行并不令人意外。描述符中的验证逻辑是根据包装类的这个属性创建一个事实上的单例;然而,很难想象这种共享状态是 Lutz 的意图,还是 intention在这个widely linked tutorial关于这个话题。

问题

是否可以创建一个描述符,使其具有包装对象所特有的内部状态,而不将该状态存储在包装对象实例上(如第一个片段中所示)?是否可以修改 linked example 中的 CardHolder 类这样 Bob 就不会变成 Sue?

最佳答案

"Like properties, descriptors are designed to handle specific attributes... Unlike properties, descriptors have their own state..."

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

你应该看到的:

Retrieving var "x"
Updating var "x"
Retrieving var "x"
Retrieving var "y"

回答你的问题:是的。但这很痛苦。

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)

关于python - python 描述符的状态去哪里了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8718052/

相关文章:

python - 如何以 pythonic 方式操作/清理 Linux 垃圾文件夹?

python - 使用 @pytest.fixture(scope ="module") 和 @pytest.mark.asyncio

python - 显示价格

python - 奇怪……[::5,0]是什么意思

python - jupyter笔记本/实验室终端python版本

Python:在文件文件夹中搜索特定字符串,然后列出包含该字符串的所有文件

python - 以编程方式同步 Django 中的数据库

java - 如何在 Python 中记录返回的列表

python - 相同模型出现在冲突模型错误中

python - ModelAdmin 查询集中跨多个表的 Django 聚合