[Python-Dev] PEP 455: TransformDict

Ryan Gonzalez rymg19 at gmail.com
Fri Sep 13 23:24:22 CEST 2013


You know, I can think up several use cases for the case-insensitive idea.

Not sure if I missed something, but there should be a function to retrieve
the original key from the modified. i.e.:

>>> mydict['SomeStr'] = 5
>>> mydict.get_key('somestr')
'SomeStr'
>>>


On Fri, Sep 13, 2013 at 1:40 PM, Antoine Pitrou <solipsis at pitrou.net> wrote:

>
> Hello,
>
> Following the python-dev discussion, I've written a PEP to recap the
> proposal and the various arguments. It's inlined below, and it will
> probably appear soon at http://www.python.org/dev/peps/pep-0455/, too.
>
> Regards
>
> Antoine.
>
>
> PEP: 455
> Title: Adding a key-transforming dictionary to collections
> Version: $Revision$
> Last-Modified: $Date$
> Author: Antoine Pitrou <solipsis at pitrou.net>
> Status: Draft
> Type: Standards Track
> Content-Type: text/x-rst
> Created: 13-Sep-2013
> Python-Version: 3.4
> Post-History:
>
>
> Abstract
> ========
>
> This PEP proposes a new data structure for the ``collections`` module,
> called "TransformDict" in this PEP.  This structure is a mutable mapping
> which transforms the key using a given function when doing a lookup, but
> retains the original key when reading.
>
>
> Rationale
> =========
>
> Numerous specialized versions of this pattern exist.  The most common
> is a case-insensitive case-preserving dict, i.e. a dict-like container
> which matches keys in a case-insensitive fashion but retains the
> original casing.  It is a very common need in network programming, as
> many protocols feature some arrays of "key / value" properties in their
> messages, where the keys are textual strings whose casing isn't
> relevant.
>
> Another common request is an identity dict, where keys are matched
> according to their respective id()s instead of normal matching.
>
> Both are instances of a more general pattern, where a given
> transformation function is applied to keys when looking them up: that
> function being ``str.lower`` in the former example and the built-in
> ``id`` function in the latter.
>
> (it can be said that the pattern *projects* keys from the user-visible
> set onto the internal lookup set, hence this PEP's title)
>
>
> Semantics
> =========
>
> TransformDict is a ``MutableMapping`` implementation: it faithfully
> implements the well-known API of mutable mappings, as ``dict`` itself
> and other dict-like classes in the standard library.  Therefore, this
> PEP won't rehash the semantics of most TransformDict methods.
>
> The transformation function needn't be bijective, it can be strictly
> surjective as in the case-insensitive example::
>
>    >>> d = TransformDict(str.lower)
>    >>> d['SomeKey'] = 5
>    >>> d['somekey']
>    5
>    >>> d['SOMEKEY']
>    5
>
> TransformDict retains the first key used when creating an entry::
>
>    >>> d = TransformDict(str.lower)
>    >>> d['SomeKey'] = 1
>    >>> d['somekey'] = 2
>    >>> list(d.items())
>    [('SomeKey', 2)]
>
> The original keys needn't be hashable, as long as the transformation
> function returns a hashable one::
>
>    >>> d = TransformDict(id)
>    >>> l = [None]
>    >>> d[l] = 5
>    >>> l in d
>    True
>
> Constructor
> -----------
>
> As shown in the example aboves, creating a TransformDict requires
> passing the key transformation function as the first argument (much
> like creating a ``defaultdict`` requires passing the factory function
> as first argument).
>
> The constructor also takes other optional arguments which can be used
> to initialize the TransformDict with certain key-value pairs.  Those
> optional arguments are the same as in the ``dict`` and ``defaultdict``
> constructors::
>
>    >>> d = TransformDict(str.lower, [('Foo': 1)], Bar=2)
>    >>> sorted(d.items())
>    [('Bar', 2), ('Foo', 1)]
>
>
> Alternative proposals and questions
> ===================================
>
> Retaining the last original key
> -------------------------------
>
> Most python-dev respondents found retaining the first user-supplied key
> more intuitive than retaining the last.  Also, it matches the dict
> object's own behaviour when using different but equal keys::
>
>    >>> d = {}
>    >>> d[1] = 'hello'
>    >>> d[1.0] = 'world'
>    >>> d
>    {1: 'world'}
>
> Furthermore, explicitly retaining the last key in a first-key-retaining
> scheme is still possible using the following approach::
>
>    d.pop(key, None)
>    d[key] = value
>
> while the converse (retaining the first key in a last-key-retaining
> scheme) doesn't look possible without rewriting part of the container's
> code.
>
> Using an encoder / decoder pair
> -------------------------------
>
> Using a function pair isn't necessary, since the original key is
> retained by the container.  Moreover, an encoder / decoder pair would
> require the transformation to be bijective, which prevents important
> use cases like case-insensitive matching.
>
> Providing a transformation function for values
> ----------------------------------------------
>
> Dictionary values are not used for lookup, their semantics are totally
> irrelevant to the container's operation.  Therefore, there is no point
> in having both an "original" and a "transformed" value: the transformed
> value wouldn't be used for anything.
>
> Providing a specialized container, not generic
> ----------------------------------------------
>
> It was asked why we would provide the generic TransformDict construct
> rather than a specialized case-insensitive dict variant.  The answer
> is that it's nearly as cheap (code-wise and performance-wise) to provide
> the generic construct, and it can fill more use cases.
>
>
> Implementation
> ==============
>
> A patch for the collections module is tracked on the bug tracker at
> http://bugs.python.org/issue18986.
>
>
> Existing work
> =============
>
> Case-insensitive dicts are a popular request:
>
> *
>
> http://twistedmatrix.com/documents/current/api/twisted.python.util.InsensitiveDict.html
> * https://mail.python.org/pipermail/python-list/2013-May/647243.html
> * https://mail.python.org/pipermail/python-list/2005-April/296208.html
> * https://mail.python.org/pipermail/python-list/2004-June/241748.html
> * http://bugs.python.org/msg197376
> * http://stackoverflow.com/a/2082169
> * http://stackoverflow.com/a/3296782
> * http://code.activestate.com/recipes/66315-case-insensitive-dictionary/
> * https://gist.github.com/babakness/3901174
> * http://www.wikier.org/blog/key-insensitive-dictionary-in-python
> * http://en.sharejs.com/python/14534
> * http://www.voidspace.org.uk/python/archive.shtml#caseless
>
> Identity dicts have been requested too:
>
> * https://mail.python.org/pipermail/python-ideas/2010-May/007235.html
> * http://www.gossamer-threads.com/lists/python/python/209527
>
> Python's own pickle module uses identity lookups for object
> memoization:
> http://hg.python.org/cpython/file/0e70bf1f32a3/Lib/pickle.py#l234
>
>
> 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
>    coding: utf-8
>    End:
>
>
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> https://mail.python.org/mailman/options/python-dev/rymg19%40gmail.com
>



-- 
Ryan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20130913/6bda162d/attachment-0001.html>


More information about the Python-Dev mailing list