Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 增强提案

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