weakref.proxy 在 Python 3.9 中变得可哈希了吗?
Did weakref.proxy became hashable in Python 3.9?
weakref.proxy(Python 版本 3.9.5)的文档说明如下:
Return a proxy to object which uses a weak reference. This supports use of the proxy in most contexts instead of requiring the explicit dereferencing used with weak reference objects. The returned object will have a type of either ProxyType or CallableProxyType, depending on whether object is callable. Proxy objects are not hashable regardless of the referent; this avoids a number of problems related to their fundamentally mutable nature, and prevent their use as dictionary keys. callback is the same as the parameter of the same name to the ref() function.
如果我理解正确,下面的代码应该会引发错误:
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: Add pass-throughs for hash() and reversed() to weakref.proxy objects
还有 associated issue.
大约一年前发生的事情。
简短回答:是的,在 weakref.proxy
中存在哈希传递,但下一个版本(3.9.6 和 3.10.0)将删除它并且 weakref.proxy
将再次引发错误例如用作字典中的键。
更长的答案:如 weakref.proxy
from Python 3.9, 3.10 and 3.11. This means using weakref.proxy
as a dictionary key will raise an error in future releases (again). The developers argued that this omission was most likely intentional and that keeping it that way will save some headaches for some users (ref).