2005-10-23 18:39:17 -04:00
|
|
|
|
PEP: 351
|
|
|
|
|
Title: The freeze protocol
|
|
|
|
|
Version: 2.5
|
2006-03-23 15:13:19 -05:00
|
|
|
|
Last-Modified: $Date$
|
2005-10-23 18:39:17 -04:00
|
|
|
|
Author: Barry A. Warsaw <barry@python.org>
|
2006-02-13 16:09:25 -05:00
|
|
|
|
Status: Rejected
|
2005-10-23 18:39:17 -04:00
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 14-Apr-2005
|
2007-06-19 00:20:07 -04:00
|
|
|
|
Post-History:
|
2005-10-23 18:39:17 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
2006-02-13 16:09:25 -05:00
|
|
|
|
Rejection Notice
|
|
|
|
|
================
|
|
|
|
|
|
|
|
|
|
This PEP was rejected. For a rationale, see `this thread on python-dev`_.
|
|
|
|
|
|
|
|
|
|
.. _this thread on python-dev: http://mail.python.org/pipermail/python-dev/2006-February/060793.html
|
|
|
|
|
|
|
|
|
|
|
2005-10-23 18:39:17 -04:00
|
|
|
|
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 "<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}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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:
|