Is there a Python class/enum for flag/bit mask operations?

Paebbels picture Paebbels · Apr 25, 2016 · Viewed 17.9k times · Source

I know of base classes Enum and IntEnum. Both are very helpful but I miss features for flag operations. I don't expect that these two classes implement my wished feature.

Let's construct an example:

class NetlistKind(IntEnum):
  Unknown = 0
  LatticeNetlist = 1
  QuartusNetlist = 2
  XSTNetlist = 4
  CoreGenNetlist = 8
  All = 15

As you can see, I'm already using IntEnum to get arithmetic features for this enum. It would be nice to have something like @unique to ensure all values are a power of two. I can do this by forking enum.unique for my needs. (I'm aware that All is an exception from that rule.)

How is such an enum used?

filter = NetlistKind.LatticeNetlist | NetlistKind.QuartusNetlist

Thanks to the underlaying int bit operations are possible and filter has an internal value of 3.

If would be nice to have a "is flag X set in filter Y" function or even better an operator. I add a magic function for x in y:

@unique
class NetlistKind(IntEnum):
  Unknown = 0
  LatticeNetlist = 1
  QuartusNetlist = 2
  XSTNetlist = 4
  CoreGenNetlist = 8
  All = 15

def __contains__(self, item):
  return  (self.value & item.value) == item.value

Usage example:

....
def GetNetlists(self, filter=NetlistKind.All):
  for entity in self._entities:
    for nl in entity.GetNetlists():
      if (nl.kind in filter):
        yield nl

def GetXilinxNetlists(self):
  return self.GetNetlists(NetlistKind.XSTNetlist | NetlistKind.CoreGenNetlist)

So the questions are:

  • Are there better ways to implement bit fields?
  • Are thete better ways to implement such an 1-D filter? I don't want to use lamdas for such a simple filter condition?
  • Is such solution already included in the Python standard library?
  • How to add this enum extension to the next Python version? :)

Open features:

  • return a list of all active flags in __str__
  • ...?

Answer

Ethan Furman picture Ethan Furman · Mar 7, 2017

Python 3.6 has added Flag and IntFlag which support the usual bit-wise operations. As a bonus, the resulting values from the bit-wise operations are still members of the original flag class, and are singletons [1].

The aenum library also has this addition and is usable back to Python 2.7.

[1] A bug exists in 3.6.0: if the psuedo-flag members are being created in threads then there may end up being duplicates; this is fixed in 3.6.1 (and never existed in aenum).