interpret an integer as enum flags

Viewed 90

Suppose I have a Flag enum like this:

From enum import Flag
class suspicion(Flag):
     TOT_PCNT_LOW = 1
     IND_PCNT_LOW = 2
     IND_SCORE_LOW = 4

And suppose I have an integer that was constructed using these flags

i = suspicion.IND_PCNT_LOW.value | suspicion.TOT_PCNT_LOW.value      # i == 3

How do I get a list of the names of the flags that are set in the integer? For example:

print(some_method(i))   # prints ["IND_PCNT_LOW", "TOT_PCNT_LOW"]
1 Answers

Setup code:

from enum import Flag
class Suspicion(Flag):
     TOT_PCNT_LOW = 1
     IND_PCNT_LOW = 2
     IND_SCORE_LOW = 4

a_flag = Suspicion.TOT_PCNT_LOW | Suspicion.IND_PCNT_LOW

In Python before 3.10

def flag_names(flag):
    return [f.name for f in flag.__class__ if f & flag == f]

It's slightly easier in 3.10+

def flag_names(flag):
    # Python 3.10+
    return [f.name for f in flag]

In either case:

print(flag_names(a_flag))

gets you

['TOT_PCNT_LOW', 'IND_PCNT_LOW']

If the incoming flag argument may be an integer instead of a Suspicion member, you can handle that as well:

def flag_names(flag, enum=None):
    """
    returns names of component flags making up flag
    if `flag` is an integer, `enum` must be enumeration to match against
    """
    if enum is None and not isinstance(flag, Flag):
        raise ValueError('`enum` must be specifed if `flag` is an `int`')
    enum = enum or flag.__class__
    return [f.name for f in enum if f & flag == f]
Related