ASPN ActiveState Programmer Network  
ActiveState, a division of Sophos
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups
Submit Recipe
My Recipes

All Recipes
All Cookbooks


View by Category

Title: Simple record (a.k.a. struct) type
Submitter: Steven Bethard (other recipes)
Last Updated: 2007/02/22
Version no: 1.5
Category:

 

4 stars 4 vote(s)


Description:

This recipe provides a simple and efficient way of creating records (a.k.a. structs) where each argument to the constructor becomes an attribute of the object.

Source: Text Source

class InitFromSlots(type):
    def __new__(meta, name, bases, bodydict):
        slots = bodydict['__slots__']
        if slots and '__init__' not in bodydict:
            parts = ['def __init__(self, %s):' % ', '.join(slots)]
            for slot in slots:
                parts.append('    self.%s = %s' % (slot, slot))
            exec '\n'.join(parts) in bodydict
        super_new =  super(InitFromSlots, meta).__new__
        return super_new(meta, name, bases, bodydict)

class Record(object):
    __metaclass__ = InitFromSlots
    __slots__ = ()
    def _items(self):
        for name in self.__slots__:
            yield name, getattr(self, name)
    def __repr__(self):
        args = ', '.join('%s=%r' % tup for tup in self._items())
        return '%s(%s)' % (type(self).__name__, args)
    def __iter__(self):
        for name in self.__slots__:
            yield getattr(self, name)
    def __getstate__(self):
        return dict(self._items())
    def __setstate__(self, statedict):
        self.__init__(**statedict)

# =========================
# At the interactive prompt
# =========================

>>> class Point(Record):
...     __slots__ = 'x', 'y'
... 
>>> Point(3, 4)
Point(x=3, y=4)
>>> Point(y=5, x=2)
Point(x=2, y=5)
>>> point = Point(-1, 42)
>>> point.x, point.y
(-1, 42)
>>> x, y = point
>>> x, y
(-1, 42)

>>> class Badger(Record):
...     __slots__ = 'large', 'wooden'
...     
>>> badger = Badger('spam', 'eggs')
>>> import pickle
>>> pickle.loads(pickle.dumps(badger))
Badger(large='spam', wooden='eggs')

>>> class Answer(Record):
...     __slots__ = 'life', 'universe', 'everything'
...     
>>> eval(repr(Answer(42, 42, 42)))
Answer(life=42, universe=42, everything=42)

Discussion:

The NamedTuple recipe (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/500261) offers a hybrid of tuples and simple record-like objects. Sometimes, however, you only need attribute-style access, not indexing. This recipe caters to such use cases.

For object creation and attribute access, this recipe will generally be faster than recipe 500261 -- __init__ is a simple sequence of assignments, and attributes are handled through fast C-level slots. For unpacking and iteration, this recipe will be slower than recipe 500261 -- __iter__ is a Python-level generator instead of C-level tuple iteration.

Update 21 Feb 07:
Record now supplies __iter__ to allow for tuple unpacking.
InitFromSlots now only adds __init__ if it is not defined.



Add comment

No comments.



Highest rated recipes:

1. A simple XML-RPC server

2. Web service accessible ...

3. IPy Notify

4. Treat the Win32 Registry ...

5. a friendly mkdir()

6. Wrapping template engine ...

7. Assignment in expression

8. Changing return value ...

9. Implementation of sets ...

10. bag collection class




Privacy Policy | Email Opt-out | Feedback | Syndication
© 2006 ActiveState Software Inc. All rights reserved.