Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Python not support record type? (i.e. mutable namedtuple)

Why does Python not support a record type natively? It's a matter of having a mutable version of namedtuple.

I could use namedtuple._replace. But I need to have these records in a collection and since namedtuple._replace creates another instance, I also need to modify the collection which becomes messy quickly.

Background: I have a device whose attributes I need to get by polling it over TCP/IP. i.e. its representation is a mutable object.

Edit: I have a set of devices for whom I need to poll.

Edit: I need to iterate through the object displaying its attributes using PyQt. I know I can add special methods like __getitem__ and __iter__, but I want to know if there is an easier way.

Edit: I would prefer a type whose attribute are fixed (just like they are in my device), but are mutable.

like image 516
Salil Avatar asked Mar 08 '11 03:03

Salil


People also ask

What is record in Python?

In Python terms, a record is an instance of any class for which you define some attributes but no methods. Such classes, which are known as record types, can be easily written but require a lot of noisy boilerplate.

Are Named tuples mutable?

Named Tuple Python's tuple is a simple data structure for grouping objects with different types. Its defining feature is being immutable.


2 Answers

Python <3.3

You mean something like this?

class Record(object):     __slots__= "attribute1", "attribute2", "attribute3",      def items(self):         "dict style items"         return [             (field_name, getattr(self, field_name))             for field_name in self.__slots__]      def __iter__(self):         "iterate over fields tuple/list style"         for field_name in self.__slots__:             yield getattr(self, field_name)      def __getitem__(self, index):         "tuple/list style getitem"         return getattr(self, self.__slots__[index])  >>> r= Record() >>> r.attribute1= "hello" >>> r.attribute2= "there" >>> r.attribute3= 3.14  >>> print r.items() [('attribute1', 'hello'), ('attribute2', 'there'), ('attribute3', 3.1400000000000001)] >>> print tuple(r) ('hello', 'there', 3.1400000000000001) 

Note that the methods provided are just a sample of possible methods.

Python ≥3.3 update

You can use types.SimpleNamespace:

>>> import types >>> r= types.SimpleNamespace() >>> r.attribute1= "hello" >>> r.attribute2= "there" >>> r.attribute3= 3.14 

dir(r) would provide you with the attribute names (filtering out all .startswith("__"), of course).

like image 154
tzot Avatar answered Oct 14 '22 14:10

tzot


Is there any reason you can't use a regular dictionary? It seems like the attributes don't have a specific ordering in your particular situation.

Alternatively, you could also use a class instance (which has nice attribute access syntax). You could use __slots__ if you wish to avoid having a __dict__ created for each instance.

I've also just found a recipe for "records", which are described as mutable named-tuples. They are implemented using classes.

Update:

Since you say order is important for your scenario (and you want to iterate through all the attributes) an OrderedDict seems to be the way to go. This is part of the standard collections module as of Python 2.7; there are other implementations floating around the internet for Python < 2.7.

To add attribute-style access, you can subclass it like so:

from collections import OrderedDict  class MutableNamedTuple(OrderedDict):     def __init__(self, *args, **kwargs):         super(MutableNamedTuple, self).__init__(*args, **kwargs)         self._initialized = True      def __getattr__(self, name):         try:             return self[name]         except KeyError:             raise AttributeError(name)      def __setattr__(self, name, value):         if hasattr(self, '_initialized'):             super(MutableNamedTuple, self).__setitem__(name, value)         else:             super(MutableNamedTuple, self).__setattr__(name, value) 

Then you can do:

>>> t = MutableNamedTuple() >>> t.foo = u'Crazy camels!' >>> t.bar = u'Yay, attribute access' >>> t.foo u'Crazy camels!' >>> t.values() [u'Crazy camels!', u'Yay, attribute access'] 
like image 34
Cameron Avatar answered Oct 14 '22 15:10

Cameron