pythonpython-3.xenums

A more pythonic way to define an enum with dynamic members


I needed to create an enum to represent the ISO country codes. The country code data comes from a json file which can be obtained from: https://github.com/lukes/ISO-3166-Countries-with-Regional-Codes

So what I've done is:

data = json.load(open('slim-2.json'))
codes_list = [(data[i]['alpha-2'], int(data[i]['country-code']))
              for i in range(len(data))]

CountryCode = enum.Enum('CountryCode', codes_list,)

names_dict = {int(data[i]['country-code']):data[i]['name'] 
              for i in range(len(data))}
setattr(CountryCode, '_names', names_dict)

CountryCode.choices = classmethod(lambda cls:((member.value, name) 
                                  for name, member in cls.__members__.items()))
setattr(CountryCode, '__str__' ,lambda self: self.__class__._names[self.value])

This code snippet is frankly ugly. I looked at alternative ways to define the enum class but couldn't piece together a solution. Is there a way to define the enum in the following form:

class CountryCode(enum.Enum):

    data = json.load(open('slim-2.json'))
    # Some code to define the enum members

    @classmethod
    def choices(cls):
    # etc...

Any suggestions on how to do this?


Solution

  • How about this?

    data = json.load(open('slim-2.json'))
    CountryCode = enum.Enum('CountryCode', [
        (x['alpha-2'], int(x['country-code'])) for x in data
    ])
    CountryCode._names = {x['alpha-2']: x['name'] for x in data}
    CountryCode.__str__ = lambda self: self._names[self.name]
    CountryCode.choices = lambda: ((e.value, e.name) for e in CountryCode)