PEP 351 – 冻结协议
- 作者:
- Barry Warsaw <barry at python.org>
- 状态:
- 已拒绝
- 类型:
- 标准跟踪
- 创建:
- 2005年4月14日
- 更新历史:
摘要
本 PEP 描述了一种用于请求可变对象的可冻结、不可变副本的简单协议。它还定义了一个新的内置函数,该函数使用此协议为任何协作对象提供不可变副本。
拒绝通知
此 PEP 已被拒绝。有关基本原理,请参阅 python-dev 上的此线程。
基本原理
内置对象(如字典和集合)仅接受不可变对象作为键。这意味着像列表这样的可变对象不能用作字典的键。但是,Python 程序员可以将列表转换为元组;这两个对象相似,但后者是不可变的,可以用作字典键。
可以设想第三方对象也具有类似的可变和不可变对应项,并且拥有一个用于转换此类对象的标准协议将非常有用。
sets.Set 对象公开了“自动转换为不可变的协议”,以便您可以创建 sets.Sets 的 sets.Sets。 PEP 218 故意从内置集合中删除了此功能。本 PEP 提出该功能仍然有用,并建议了一种支持它的标准机制。
提案
建议添加一个名为 freeze() 的新内置函数。
如果将不可变对象传递给 freeze(),则通过对该对象调用 hash() 不引发 TypeError 来确定,则直接返回该对象。
如果将可变对象(即对该对象调用 hash() 引发 TypeError)传递给 freeze(),则 freeze() 将调用该对象的 __freeze__() 方法以获取不可变副本。如果该对象没有 __freeze__() 方法,则会引发 TypeError。
示例实现
这是一个 freeze() 内置函数的 Python 实现
def freeze(obj):
try:
hash(obj)
return obj
except TypeError:
freezer = getattr(obj, '__freeze__', None)
if freezer:
return freezer()
raise TypeError('object is not freezable')``
以下是一些代码示例,显示了预期的语义
class xset(set):
def __freeze__(self):
return frozenset(self)
class xlist(list):
def __freeze__(self):
return tuple(self)
class imdict(dict):
def __hash__(self):
return id(self)
def _immutable(self, *args, **kws):
raise TypeError('object is immutable')
__setitem__ = _immutable
__delitem__ = _immutable
clear = _immutable
update = _immutable
setdefault = _immutable
pop = _immutable
popitem = _immutable
class xdict(dict):
def __freeze__(self):
return imdict(self)
>>> s = set([1, 2, 3])
>>> {s: 4}
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: set objects are unhashable
>>> t = freeze(s)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/usr/tmp/python-lWCjBK.py", line 9, in freeze
TypeError: object is not freezable
>>> t = xset(s)
>>> u = freeze(t)
>>> {u: 4}
{frozenset([1, 2, 3]): 4}
>>> x = 'hello'
>>> freeze(x) is x
True
>>> d = xdict(a=7, b=8, c=9)
>>> hash(d)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: dict objects are unhashable
>>> hash(freeze(d))
-1210776116
>>> {d: 4}
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: dict objects are unhashable
>>> {freeze(d): 4}
{{'a': 7, 'c': 9, 'b': 8}: 4}
参考实现
补丁 1335812 提供了此功能的 C 实现。它添加了 freeze() 内置函数,以及列表和集合的 __freeze__() 方法的实现。字典在当前的 Python 中不容易冻结,因此尚未提供 dict.__freeze__() 的实现。
未解决的问题
- 我们是否应该为解冻冻结的对象定义类似的协议?
- 字典和集合是否应该自动冻结它们的可变键?
- 我们是否应该支持“临时冻结”(也许使用名为 __congeal__() 的方法)类似于 sets.Set 中的 __as_temporarily_immutable__()?
- 为了与 sets.Set 向后兼容,我们是否应该支持 __as_immutable__()?或者是否应该将 __freeze__() 重命名为 __as_immutable__()?
版权
本文档已进入公有领域。
来源: https://github.com/python/peps/blob/main/peps/pep-0351.rst
上次修改时间: 2023年9月9日 17:39:29 GMT