PEP: 351 Title: The freeze protocol Version: 2.5 Author: Barry A. Warsaw Status: Active Type: Standards Track Content-Type: text/x-rst Created: 14-Apr-2005 Abstract ======== This PEP describes a simple protocol for requesting a frozen, immutable copy of a mutable object. It also defines a new built-in function which uses this protocol to provide an immutable copy on any cooperating object. Rationale ========= Built-in objects such dictionaries and sets accept only immutable objects as keys. This means that mutable objects like lists cannot be used as keys to a dictionary. However, a Python programmer can convert a list to a tuple; the two objects are similar, but the latter is immutable, and can be used as a dictionary key. It is conceivable that third party objects also have similar mutable and immutable counterparts, and it would be useful to have a standard protocol for conversion of such objects. sets.Set objects expose a "protocol for automatic conversion to immutable" so that you can create sets.Sets of sets.Sets. PEP 218 deliberately dropped this feature from built-in sets. This PEP advances that the feature is still useful and proposes a standard mechanism for its support. Proposal ======== It is proposed that a new built-in function called freeze() is added. If freeze() is passed an immutable object, as determined by hash() on that object not raising a TypeError, then the object is returned directly. If freeze() is passed a mutable object (i.e. hash() of that object raises a TypeError), then freeze() will call that object's __freeze__() method to get an immutable copy. If the object does not have a __freeze__() method, then a TypeError is raised. Sample implementations ====================== Here is a Python implementation of the freeze() built-in:: 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')`` Here are some code samples which show the intended semantics:: 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 "", line 1, in ? TypeError: set objects are unhashable >>> t = freeze(s) Traceback (most recent call last): File "", 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 "", line 1, in ? TypeError: dict objects are unhashable >>> hash(freeze(d)) -1210776116 >>> {d: 4} Traceback (most recent call last): File "", line 1, in ? TypeError: dict objects are unhashable >>> {freeze(d): 4} {{'a': 7, 'c': 9, 'b': 8}: 4} Reference implementation ======================== Patch 1335812_ provides the C implementation of this feature. It adds the freeze() built-in, along with implementations of the __freeze__() method for lists and sets. Dictionaries are not easily freezable in current Python, so an implementation of dict.__freeze__() is not provided yet. .. _1335812: http://sourceforge.net/tracker/index.php?func=detail&aid=1335812&group_id=5470&atid=305470 Open issues =========== - Should we define a similar protocol for thawing frozen objects? - Should dicts and sets automatically freeze their mutable keys? - Should we support "temporary freezing" (perhaps with a method called __congeal__()) a la __as_temporarily_immutable__() in sets.Set? - For backward compatibility with sets.Set, should we support __as_immutable__()? Or should __freeze__() just be renamed to __as_immutable__()? Copyright ========= This document has been placed in the public domain. .. Local Variables: mode: indented-text indent-tabs-mode: nil sentence-end-double-space: t fill-column: 70 End: