微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Python 3.9 中,weakref.proxy 变得可哈希了吗?

如何解决在 Python 3.9 中,weakref.proxy 变得可哈希了吗?

weakref.proxy(Python 3.9.5 版)的文档说明如下:

将代理返回给使用弱引用的对象。这支持在大多数上下文中使用代理,而不需要与弱引用对象一起使用的显式取消引用。返回的对象将具有 ProxyType 或 CallableProxyType 的类型,具体取决于对象是否可调用代理对象是不可散列的,无论所指对象如何;这避免了一些与其基本可变性质相关的问题,并防止将它们用作字典键。 callback 与 ref() 函数的同名参数相同。

如果我理解正确,以下代码应该会引发错误

import weakref


class Model:
    pass


m = Model()
proxy = weakref.proxy(m)
d = {proxy: 1}
assert d[proxy] == 1

Python 3.8 也是如此:

  File "...",line 11,in <module>
    d = {proxy: 1}
TypeError: unhashable type: 'weakproxy'

但是,代码在 Python 3.9.5 上运行得很好!

Python 3.9.5 (default,May 18 2021,14:42:02) [MSC v.1916 64 bit (AMD64)] :: Anaconda,Inc. on win32
Type "help","copyright","credits" or "license" for more information.
>>> import weakref
>>>
>>>
>>> class Model:
...     pass
...
>>>
>>> m = Model()
>>> proxy = weakref.proxy(m)
>>> print(type(proxy))
<class 'weakproxy'>
>>> d = {proxy: 1}
>>> assert d[proxy] == 1
>>> d
{<weakproxy at 0x000001E3DCF665E0 to Model at 0x000001E3DC9DA100>: 1}

如果使用 print(hash(proxy))代码可能会更短,这再次为 Python 3.8 引发 TypeError 而不是 Python 3.9:

import weakref

class Model:
    pass

m = Model()
proxy = weakref.proxy(m)
ref = weakref.ref(m)
print(hash(m))     # >>> 159803004579 (Python 3.8 + 3.9)
print(hash(ref))   # >>> 159803004579 (Python 3.8 + 3.9)
print(hash(proxy)) # >>> TypeError (Python 3.8) 159803004579 (Python 3.9)

这是否意味着 weakref.proxy 现在是可散列的,即使文档另有说明,还是我在这里遗漏了一些基本的东西?

解决方法

是的,它似乎已经改变了。 This commit 说:

bpo-40523:将 hash() 和 reversed() 的传递添加到 weakref.proxy 对象

还有 associated issue

它发生在大约一年前。

,

简短回答:是的,weakref.proxy 中有一个哈希传递,但下一个版本(3.9.6 和 3.10.0)将删除它,weakref.proxy 将在用于实例作为字典中的键。

更长的答案:正如 Carcigenicate 在他的回答中提到的,2020 年 5 月的哈希传递是 committed。我提交了 an issue,因为文档似乎已经过时。但是,经过一些讨论后,决定 revert 到旧行为并从 Python 3.9、3.10 和 3.11 中删除 weakref.proxy 的传递。这意味着使用 weakref.proxy 作为字典键将在未来版本中引发错误(再次)。开发人员认为,这种遗漏很可能是有意为之,保持这种状态会为某些用户 (ref) 省去一些麻烦。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。