Existence of mutable named tuple in Python?

python namedtuple
python namedlist
python deque
python recordclass
python simplenamespace
python dataclass
python namedtuple defaults
python editable namedtuple

Can anyone amend namedtuple or provide an alternative class so that it works for mutable objects?

Primarily for readability, I would like something similar to namedtuple that does this:

from Camelot import namedgroup

Point = namedgroup('Point', ['x', 'y'])
p = Point(0, 0)
p.x = 10

>>> p
Point(x=10, y=0)

>>> p.x *= 10
Point(x=100, y=0)

It must be possible to pickle the resulting object. And per the characteristics of named tuple, the ordering of the output when represented must match the order of the parameter list when constructing the object.

There is a mutable alternative to collections.namedtuple - recordclass.

It has the same API and memory footprint as namedtuple and it supports assignments (It should be faster as well). For example:

from recordclass import recordclass

Point = recordclass('Point', 'x y')

>>> p = Point(1, 2)
>>> p
Point(x=1, y=2)
>>> print(p.x, p.y)
1 2
>>> p.x += 2; p.y += 3; print(p)
Point(x=3, y=5)

For python 3.6 and higher recordclass (since 0.5) support typehints:

from recordclass import recordclass, RecordClass

class Point(RecordClass):
   x: int
   y: int

>>> Point.__annotations__
{'x':int, 'y':int}
>>> p = Point(1, 2)
>>> p
Point(x=1, y=2)
>>> print(p.x, p.y)
1 2
>>> p.x += 2; p.y += 3; print(p)
Point(x=3, y=5)

There is a more complete example (it also includes performance comparisons).

Since 0.9 recordclass library provides another variant -- recordclass.structclass factory function. It can produce classes, whose instances occupy less memory than __slots__-based instances. This is can be important for the instances with attribute values, which has not intended to have reference cycles. It may help reduce memory usage if you need to create millions of instances. Here is an illustrative example.

recordclass · PyPI, namedtuple(). factory function for creating tuple subclasses with named fields. New in version 2.6. deque. list-like container with fast appends and pops on either  Named Tuple can be a great alternative here to construct a class. Named Tuple is basically an extension of the Python built-in tuple data type. Python’s tuple is a simple data structure for grouping objects with different types. Its defining feature is being immutable. An immutable object is an object whose state cannot be modified after it is created. In Python, immutable types are int, float, bool, str, tuple and unicode.

types.SimpleNamespace was introduced in Python 3.3 and supports the requested requirements.

from types import SimpleNamespace
t = SimpleNamespace(foo='bar')
t.ham = 'spam'
print(t)
namespace(foo='bar', ham='spam')
print(t.foo)
'bar'
import pickle
with open('/tmp/pickle', 'wb') as f:
    pickle.dump(t, f)

8.3. collections — High-performance container datatypes, If you want to deep dive into Named Tuple and Dataclass, check out the In Python, immutable types are int, float, bool, str, tuple and unicode. One is from collections package which has existed for a long time, the other  Namedtuple in Python Python supports a type of container like dictionaries called “ namedtuples () ” present in module, “ collections “. Like dictionaries they contain keys that are hashed to a particular value. But on contrary, it supports both access from key value and iteration, the functionality that dictionaries lack.

The latest namedlist 1.7 passes all of your tests with both Python 2.7 and Python 3.5 as of Jan 11, 2016. It is a pure python implementation whereas the recordclass is a C extension. Of course, it depends on your requirements whether a C extension is preferred or not.

Your tests (but also see the note below):

from __future__ import print_function
import pickle
import sys
from namedlist import namedlist

Point = namedlist('Point', 'x y')
p = Point(x=1, y=2)

print('1. Mutation of field values')
p.x *= 10
p.y += 10
print('p: {}, {}\n'.format(p.x, p.y))

print('2. String')
print('p: {}\n'.format(p))

print('3. Representation')
print(repr(p), '\n')

print('4. Sizeof')
print('size of p:', sys.getsizeof(p), '\n')

print('5. Access by name of field')
print('p: {}, {}\n'.format(p.x, p.y))

print('6. Access by index')
print('p: {}, {}\n'.format(p[0], p[1]))

print('7. Iterative unpacking')
x, y = p
print('p: {}, {}\n'.format(x, y))

print('8. Iteration')
print('p: {}\n'.format([v for v in p]))

print('9. Ordered Dict')
print('p: {}\n'.format(p._asdict()))

print('10. Inplace replacement (update?)')
p._update(x=100, y=200)
print('p: {}\n'.format(p))

print('11. Pickle and Unpickle')
pickled = pickle.dumps(p)
unpickled = pickle.loads(pickled)
assert p == unpickled
print('Pickled successfully\n')

print('12. Fields\n')
print('p: {}\n'.format(p._fields))

print('13. Slots')
print('p: {}\n'.format(p.__slots__))

Output on Python 2.7

1. Mutation of field values  
p: 10, 12

2. String  
p: Point(x=10, y=12)

3. Representation  
Point(x=10, y=12) 

4. Sizeof  
size of p: 64 

5. Access by name of field  
p: 10, 12

6. Access by index  
p: 10, 12

7. Iterative unpacking  
p: 10, 12

8. Iteration  
p: [10, 12]

9. Ordered Dict  
p: OrderedDict([('x', 10), ('y', 12)])

10. Inplace replacement (update?)  
p: Point(x=100, y=200)

11. Pickle and Unpickle  
Pickled successfully

12. Fields  
p: ('x', 'y')

13. Slots  
p: ('x', 'y')

The only difference with Python 3.5 is that the namedlist has become smaller, the size is 56 (Python 2.7 reports 64).

Note that I have changed your test 10 for in-place replacement. The namedlist has a _replace() method which does a shallow copy, and that makes perfect sense to me because the namedtuple in the standard library behaves the same way. Changing the semantics of the _replace() method would be confusing. In my opinion the _update() method should be used for in-place updates. Or maybe I failed to understand the intent of your test 10?

Understand how to use NamedTuple and Dataclass in Python, That's very much like the classes built by namedtuple, but mutable. I propose Or maybe it _does_ exist in Python, and it is a matter of having a The above tuple t contains elements of different data types, the first one is an immutable string and the second one is a mutable list.The tuple itself isn’t mutable . i.e. it doesn’t have any

It seems like the answer to this question is no.

Below is pretty close, but it's not technically mutable. This is creating a new namedtuple() instance with an updated x value:

Point = namedtuple('Point', ['x', 'y'])
p = Point(0, 0)
p = p._replace(x=10) 

On the other hand, you can create a simple class using __slots__ that should work well for frequently updating class instance attributes:

class Point:
    __slots__ = ['x', 'y']
    def __init__(self, x, y):
        self.x = x
        self.y = y

To add to this answer, I think __slots__ is good use here because it's memory efficient when you create lots of class instances. The only downside is that you can't create new class attributes.

Here's one relevant thread that illustrates the memory efficiency - Dictionary vs Object - which is more efficient and why?

The quoted content in the answer of this thread is a very succinct explanation why __slots__ is more memory efficient - Python slots

[Python-ideas] A mutable alternative to namedtuple, Your abstract base class MutableNamedTuple is directly instantiable. try to address the above issues using meta-programming and other features of Python 3: Subclass and define your named fields with __slots__. Whereas mutable objects are easy to change. Use of mutable objects is recommended when there is a need to change the size or content of the object. Exception : However, there is an exception in immutability as well. We know that tuple in python is immutable. But the tuple consists of a sequence of names with unchangeable bindings to objects.

As a very Pythonic alternative for this task, since Python-3.7, you can use dataclasses module that not only behaves like a mutable NamedTuple because they use normal class definitions they also support other classes features.

From PEP-0557:

Although they use a very different mechanism, Data Classes can be thought of as "mutable namedtuples with defaults". Because Data Classes use normal class definition syntax, you are free to use inheritance, metaclasses, docstrings, user-defined methods, class factories, and other Python class features.

A class decorator is provided which inspects a class definition for variables with type annotations as defined in PEP 526, "Syntax for Variable Annotations". In this document, such variables are called fields. Using these fields, the decorator adds generated method definitions to the class to support instance initialization, a repr, comparison methods, and optionally other methods as described in the Specification section. Such a class is called a Data Class, but there's really nothing special about the class: the decorator adds generated methods to the class and returns the same class it was given.

This feature is introduced in PEP-0557 that you can read about it in more details on provided documentation link.

Example:

In [20]: from dataclasses import dataclass

In [21]: @dataclass
    ...: class InventoryItem:
    ...:     '''Class for keeping track of an item in inventory.'''
    ...:     name: str
    ...:     unit_price: float
    ...:     quantity_on_hand: int = 0
    ...: 
    ...:     def total_cost(self) -> float:
    ...:         return self.unit_price * self.quantity_on_hand
    ...:    

Demo:

In [23]: II = InventoryItem('bisc', 2000)

In [24]: II
Out[24]: InventoryItem(name='bisc', unit_price=2000, quantity_on_hand=0)

In [25]: II.name = 'choco'

In [26]: II.name
Out[26]: 'choco'

In [27]: 

In [27]: II.unit_price *= 3

In [28]: II.unit_price
Out[28]: 6000

In [29]: II
Out[29]: InventoryItem(name='choco', unit_price=6000, quantity_on_hand=0)

Mutable Named Tuple - or - Slotted Data Structure, namedtuple(), factory function for creating tuple subclasses with named fields. deque, list-like container Example of simulating Python's internal lookup chain: SimpleNamespace() for a mutable namespace based on an underlying dictionary instead of a tuple. See typing. Raises KeyError if the key does not exist: >>> The main objective of this article is to make a brief introduction related to python3: the methods id() and type(), mutable and immutable objects and their differences, and the implications of the…

8.3. collections — Container datatypes, What makes a >>> colors[0] python tuple unique is that its values cannot be changed, i.e., it is immutable. Let's try changing a value. recordclass is a mutable version of collection.namedtuple that inherits it's api, memory footprint, but support assignments. namedlist is actually instance of python class with slots. It's more usefull if you don't need fast access to it's fields by index. – intellimath Dec 20 '16 at 19:34.

Python Namedtuple, Existence of mutable named tuple in Python?, There is a mutable alternative to collections.namedtuple - recordclass. It has the same API and memory footprint  Python provides an elegant solution – named tuples. A named tuple is exactly like a normal tuple, except that the fields can also be accessed by.fieldname. Named tuples are still immutable, you can still index elements with integers, and you can iterate over the elements.

namedtuple._replace() doesn't work as described in the , Recordclass: mutable namedtuple without cyclic GC .com/questions/29290359​/existence-of-mutable-named-tuple-in -python / 29419745). This is why people say that Python passes neither by value or reference, but instead by “call by object reference”. In conclusion, mutable objects in Python include: list, dictionary, set, and byte array. Immutable objects include: int, float, complex, tuple, string, frozen set, bytes.

Comments
  • See also: stackoverflow.com/q/5131044. Is there a reason you can't just use a dictionary?
  • @senshin Thanks for the link. I prefer not to use a dictionary for the reason pointed out in it. That response also linked to code.activestate.com/recipes/…, which is pretty close to what I'm after.
  • Unlike with namedtuples, it appears you have no need to be able to reference the attributes by index, i.e. so p[0] and p[1] would be alternate ways to reference x and y respectively, correct?
  • Ideally, yes, indexable by position like a plain tuple in addition to by name, and unpacks like a tuple. This ActiveState recipe is close, but I believe it uses a regular dictionary instead of an OrderedDict. code.activestate.com/recipes/500261
  • A mutable namedtuple is called a class.
  • Like it. 'This library actually is a "proof of concept" for the problem of "mutable" alternative of named tuple.`
  • recordclass is slower, takes more memory, and requires C-extensions as compared with Antti Haapala's recipe and namedlist.
  • recordclass is a mutable version of collection.namedtuple that inherits it's api, memory footprint, but support assignments. namedlist is actually instance of python class with slots. It's more usefull if you don't need fast access to it's fields by index.
  • Attribute access for recordclass instance (python 3.5.2) is about 2-3% slower than for namedlist
  • When using namedtuple and simple class creation Point = namedtuple('Point', 'x y'), Jedi can autocomplete attributes, while this is not the case for recordclass. If I use the longer creation code (based on RecordClass), then Jedi understands the Point class, but not its constructor or attributes... Is there a way to get recordclass to work nicely with Jedi?
  • I've been looking for something like this for years. Great replacement for a dotted dict library like dotmap
  • This needs more upvotes. It’s exactly what the OP was looking for, it’s in the standard library, and it could not be simpler to use. Thanks!
  • -1 The OP made it very clear with his tests what he needs and SimpleNamespace fails tests 6-10 (access by index, iterative unpacking, iteration, ordered dict, in-place replacement) and 12, 13 (fields, slots). Note that the documentation (that you linked in the answer) specifically says "SimpleNamespace may be useful as a replacement for class NS: pass. However, for a structured record type use namedtuple() instead."
  • There is important nuance. The namedlist store values in the list instance. The thing is that cpython's list is actually a dynamic array. By design, it allocates more memory than necessary in order to make mutation of the list cheaper.