21

I want to create a namedtuple which represents the individual flags in a short bitfield. I'm trying to subclass it so that I can unpack the bitfield before the tuple is created. However, my current attempt isn't working:

class Status(collections.namedtuple("Status", "started checking start_after_check checked error paused queued loaded")):
    __slots__ = ()

    def __new__(cls, status):
        super(cls).__new__(cls, status & 1, status & 2, status & 4, status & 8, status & 16, status & 32, status & 64, status & 128)

Now, my experience with super() is limited and my experience with __new__ is virtually non-existent, so I'm not quite sure what to make of the (to me) enigmatic error TypeError: super.__new__(Status): Status is not a subtype of super. Googling and digging into the docs haven't yielded anything enlightening.

Help?

Ben Blank
  • 54,908
  • 28
  • 127
  • 156

2 Answers2

20

You almost had it :-) There are just two little corrections:

  1. The new method needs a return statement
  2. The super call should have two arguments, cls and Status

The resulting code looks like this:

import collections

class Status(collections.namedtuple("Status", "started checking start_after_check checked error paused queued loaded")):
    __slots__ = ()

    def __new__(cls, status):
        return super(cls, Status).__new__(cls, status & 1, status & 2, status & 4, status & 8, status & 16, status & 32, status & 64, status & 128)

It runs cleanly, just like you had expected:

>>> print Status(47)
Status(started=1, checking=2, start_after_check=4, checked=8, error=0, paused=32, queued=0, loaded=0)
Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
10

I'd avoid super unless you're explicitly catering to multiple inheritance (hopefully not the case here;-). Just do something like...:

def __new__(cls, status):
    return cls.__bases__[0].__new__(cls,
                                    status & 1, status & 2, status & 4,
                                    status & 8, status & 16, status & 32,
                                    status & 64, status & 128)
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 6
    you could also reduce code duplication by using this: `return cls.__bases__[0].__new__(cls, *(status & (1 << x) for x in range(0, 8)))` – thejoshwolfe Jul 31 '11 at 02:08