PEP 351 – 冻结协议
- 作者:
- Barry Warsaw <barry at python.org>
- 状态:
- 已拒绝
- 类型:
- 标准跟踪
- 创建日期:
- 2005年4月14日
- Python 版本:
- 2.5
- 发布历史:
摘要
本PEP描述了一个简单的协议,用于请求可变对象的冻结、不可变副本。它还定义了一个新的内置函数,该函数使用此协议为任何协作对象提供不可变副本。
拒绝通知
此PEP被拒绝。原因请参见python-dev上的此讨论串。
基本原理
字典和集合等内置对象只接受不可变对象作为键。这意味着列表等可变对象不能用作字典的键。然而,Python程序员可以将列表转换为元组;这两个对象相似,但后者是不可变的,可以用作字典键。
可以想象,第三方对象也有类似的可变和不可变对应物,并且拥有一个用于此类对象转换的标准协议将非常有用。
sets.Set对象公开了一个“自动转换为不可变的协议”,以便您可以创建sets.Set的sets.Set。 PEP 218故意从内置集合中删除了此功能。本PEP提出此功能仍然有用,并提出了一个支持它的标准机制。
提案
建议添加一个名为freeze()的新内置函数。
如果freeze()传入一个不可变对象(通过在该对象上调用hash()没有引发TypeError来确定),则直接返回该对象。
如果freeze()传入一个可变对象(即该对象的hash()引发TypeError),则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