Take the 2-minute tour ×

I want to have immutable types that can, ideally, sort out their own hashing and equality, but can be easily subclassed. I started off using namedtuple:

class Command(namedtuple('Command', 'cmd_string')):

  def valid_msg(msg):
    return True

  def make_command(msg):
    if self.valid_msg(msg):
      return '%s:%s' % (self.cmd_string, msg)
      raise ValueError(INVALID_MSG)

...but this does not lend itself to subclassing. Directly subclassing this means that the name of the tuple remains the same (for printing... not such a big deal), but more importantly you can't add fields:

class LimitedLengthCommand(Command):

  # I want to have self.length! Where does it go?

  def valid_msg(msg):
    return len(msg) <= self.length

Simply creating another named tuple (as per the docs) means I don't inherit any methods!

What is the simplest and easiest way to do something like this? I intend to have multiple subclasses of Command (eg. hex literals, 1-or-0, etc), but nothing complicated. Playing nice with multiple inheritance is not essential.

share|improve this question
i've never done it and it's currently given me trouble but I know you do it by using __new__ instead of __init__ to make any modifications. I'll post when I figure it out. –  aaronasterling Oct 11 '10 at 8:05
Yeah, I know you can subclass tuple with __new__, but I'd like named fields too. –  detly Oct 11 '10 at 8:07
do you need to be able to test them with issubclass? –  aaronasterling Oct 11 '10 at 8:48
Probably not. There will be some degree of reflection on them (so that classes can generate methods for each command), but that shouldn't involve type hierarchy information. –  detly Oct 11 '10 at 8:50

1 Answer 1

up vote 1 down vote accepted

Here's a metaclass to do what you want (I think). It works by storing the methods to be inherited in a dictionary and manually inserting them into the new classes dictionary. It also stores the attribute string that gets passed to the namedtuple constructor and merges that with the attribute string from the subclass. It then passes that to namedtuple and returns a class that's inherited from the resulting namedtuple with all appropriate methods in its dictionary. Because the metaclass is derived from abc.ABCMeta, you get working type checking for free. Here's how constructing a couple of classes looks:

class Foo(object):
    __metaclass__ = ImmutableMeta
    _attributes_ = 'a b'

    def sayhi(self):
        print "Hello from {0}".format(type(self).__name__)

class Bar(Foo):
    _attributes_ = 'c'

    def saybye(self):
        print "Goodbye from {0}".format(type(self).__name__)

Here's the metaclass:

import collections as co
import abc

class ImmutableMeta(abc.ABCMeta):

    _classes = {}

    def __new__(meta, clsname, bases, clsdict):
        attributes = clsdict.pop('_attributes_')

        if bases[0] is object:
            # 'new' class
            methods = clsdict
            # we're 'inheriting' from an existing class
            base = bases[0]
            attributes = meta._classes[base]['attributes'] + ' ' + attributes
            base_methods = meta._classes[base]['methods'].copy()
            methods = base_methods

        # construct the actual base class and create the return class
        new_base = co.namedtuple(clsname + 'Base', attributes)
        cls = super(ImmutableMeta, meta).__new__(meta, clsname, (new_base,),

        # register the data necessary to 'inherit' from the class
        # and make sure that it passes typechecking
        meta._classes[cls] = {'attributes': attributes,
                              'methods': methods}
        if bases[0] is not object:
        return cls

And here's some paltry test code.

a = Foo(1, 2)

b = Bar(1, 2, 3)
b.sayhi()  # 'inherited' from class Foo

    b.c = 1         # will raise an AttributeError
except AttributeError:
    print "Immutable"

print "issubclass(Bar, Foo): {0}".format(issubclass(Bar, Foo))

   d =  {b: 1}        # No problems
except TypeError:
    print "Cant put it in a dict"
    print "Can put it in a dict"

Hope that helps. If you would prefer not to attach every method to every class that is supposed to inherit it, you could also provide a default __getattr__ that looks through the metaclasses dictionary and finds the appropriate method out of that. That would require somehow hardcoding the baseclass into method, probably using a closure.

share|improve this answer
Sorry, my time has been hijacked, so give me a couple of days and I'll try it out. But it looks like a good solution :) –  detly Oct 13 '10 at 2:07

Your Answer


