mutabletuple

Similar to namedlist, but with additional features (nested class, recursive merge, etc).


License
MIT
Install
pip install mutabletuple==0.2

Documentation

============= mutabletuple

Overview

Similar to namedlist, but with additional features:

  • Print like a native python dictionary
  • Improve support for nested mutabletuple
  • Conversion to dictionary is done recursively
  • Can iterate using iteritems like dictionary
  • Merge nested mutable tuple from dict or other mutabletuple
  • MtFactory support arguments
  • Nested pickle support

Warning Pickling works, but only for mutabletuple with default values.

Typical usage

You can use mutabletuple like a mutable namedtuple::

>>> from mutabletuple import mutabletuple
>>> from collections import OrderedDict

>>> Point = mutabletuple('Point', 'x y')
>>> p = Point(1, 3)
>>> p.x = 2
>>> assert p.x == 2
>>> assert p.y == 3

Or, you can specify a default value for all fields::

>>> Point = mutabletuple('Point', ['x', 'y'], default=3)
>>> p = Point(y=2)
>>> assert p.x == 3
>>> assert p.y == 2

Or, you can specify per-field default values::

>>> Point = mutabletuple('Point', [('x', 0), ('y', 100)])
>>> p = Point()
>>> assert p.x == 0
>>> assert p.y == 100

If you use a mapping, the value MtNoDefault is convenient to specify that a field uses the default value::

>>> from mutabletuple import MtNoDefault
>>> Point = mutabletuple('Point', OrderedDict((('y', MtNoDefault),
...                                            ('x', 100))),
...                                            default=5)
>>> p = Point()
>>> assert p.x == 100
>>> assert p.y == 5

Namedlist-like behavior

A mutabletuple behaves almost like a namedlist. Check the documentation of namedlist for more details: https://pypi.python.org/pypi/namedlist

Additional features

Additional class members

mutabletuple class contain these members:

  • _asdict(): Returns a dict which maps field names to their corresponding values.

  • _fields: Tuple of strings listing the field names. Useful for introspection.

  • merge: Recursively merge with a dict or another mutabletuple.

  • orderedDict: Recursively convert a mutabletuple into an ordered dict.

  • iteritems: To iterate like a dict.

Mutable default values

For mutabletuple, be aware of specifying mutable default values. Due to the way Python handles default values, each instance of a mutabletuple will share the default. This is especially problematic with default values that are lists. For example::

>>> A = mutabletuple('A', [('x', [])])
>>> a = A()
>>> a.x.append(4)
>>> b = A()
>>> assert b.x == [4]

This is probably not the desired behavior, so see the next section.

Specifying a factory function for default values

For mutabletuple, you can supply a zero-argument callable for a default, by wrapping it in a MtFactory call. The only change in this example is to change the default from [] to MtFactory(list). But note that b.x is a new list object, not shared with a.x::

>>> from mutabletuple import MtFactory
>>> A = mutabletuple('A', [('x', MtFactory(list))])
>>> a = A()
>>> a.x.append(4)
>>> b = A()
>>> assert b.x == []

Every time a new instance is created, your callable (in this case, list), will be called to produce a new instance for the default value.

Specifying arguments to a factory function

When using nested mutabletuple, you might want to provide arguments for the creation of nested mutabletuple. Here is an example of how to do it::

>>> Point  = mutabletuple('Point', [('x', 0), ('y', 0)])
>>> Vector = mutabletuple('Vector', [('p1', MtFactory(Point, 2)),
...                                  ('p2', MtFactory(Point, 4, 8))])
>>> v1     = Vector()
>>> assert(v1 == Vector(Point(2, 0), Point(4, 8)))

Initialized points are created every time a vector is created.

Merging mutabletuple with mutabletuple or dict

When working with nested mutabletuple, it might be useful to be able to merge recursively with a dictionary that represents only a subset of the mutabletuple::

>>> Point  = mutabletuple('Point', [('x', 0), ('y', 0)])
>>> Vector = mutabletuple('Vector', [('p1', MtFactory(Point)),
...                                  ('p2', MtFactory(Point))])
>>> Shape  = mutabletuple('Shape', [('v1', MtFactory(Vector)),
...                                 ('v2', MtFactory(Vector))])
>>> s = Shape()
>>> d = {'v1': {'p1': {'x': 20}, 'p2': Point(30, 40)}}
>>> s.merge(d)
>>> assert(s._asdict() == {
...     'v1': {'p1': {'x': 20, 'y': 0}, 'p2': {'x': 30, 'y': 40}},
...     'v2': {'p1': {'x': 0, 'y': 0}, 'p2': {'x': 0, 'y': 0}}})

Iterating over instances

Because instances are iterable (like lists or tuples), iteration works the same way. Values are returned in definition order::

>>> Point = mutabletuple('Point', 'x y z t')
>>> p = Point(1.0, 42.0, 3.14, 2.71828)
>>> for value in p:
...    print(value)
1.0
42.0
3.14
2.71828

Creating and using instances

Because the type returned by mutabletuple is a normal Python class, you create instances as you would with any Python class.