Pet*_*ite 6 python enums python-3.x
我需要创建一个枚举来表示 ISO 国家/地区代码。国家/地区代码数据来自 json 文件,可从以下位置获取:https ://github.com/lukes/ISO-3166-Countries-with-Regional-Codes
所以我所做的是:
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])
Run Code Online (Sandbox Code Playgroud)
坦率地说,这段代码片段很丑陋。我研究了定义枚举类的替代方法,但无法拼凑出解决方案。有没有一种方法可以按以下形式定义枚举:
class CountryCode(enum.Enum):
data = json.load(open('slim-2.json'))
# Some code to define the enum members
@classmethod
def choices(cls):
# etc...
Run Code Online (Sandbox Code Playgroud)
关于如何执行此操作有什么建议吗?
在何时应该子类化 EnumMeta 而不是 Enum? 的JSONEnum底部使用 , 你可以这样做:
class Country(JSONEnum):
_init_ = 'abbr code country_name' # remove if not using aenum
_file = 'some_file.json'
_name = 'alpha-2'
_value = {
1: ('alpha-2', None),
2: ('country-code', lambda c: int(c)),
3: ('name', None),
}
Run Code Online (Sandbox Code Playgroud)
看起来您正在尝试跟踪三项数据:
您应该考虑使用受 mixin 启发的技术,namedtuple如本答案所示:
标准库方式
我们需要一个基类来保存行为:
from enum import Enum
import json
class BaseCountry(Enum):
def __new__(cls, record):
member = object.__new__(cls)
member.country_name = record['name']
member.code = int(record['country-code'])
member.abbr = record['alpha-2']
member._value_ = member.abbr, member.code, member.country_name
if not hasattr(cls, '_choices'):
cls._choices = {}
cls._choices[member.code] = member.country_name
cls._choices[member.abbr] = member.country_name
return member
def __str__(self):
return self.country_name
@classmethod
def choices(cls):
return cls._choices.copy()
Run Code Online (Sandbox Code Playgroud)
然后我们可以使用它来创建实际的Country类:
Country = BaseCountry(
'Country',
[(rec['alpha-2'], rec) for rec in json.load(open('slim-2.json'))],
)
Run Code Online (Sandbox Code Playgroud)
方式aenum 1 2
from aenum import Enum, MultiValue
import json
class Country(Enum, init='abbr code country_name', settings=MultiValue):
_ignore_ = 'this country' # do not add these names as members
# create members
this = vars()
for country in json.load(open('slim-2.json')):
this[country['alpha-2']] = (
country['alpha-2'],
int(country['country-code']),
country['name'],
)
# return a dict of choices by abbr or country code to name
@classmethod
def choices(cls):
mapping = {}
for member in cls:
mapping[member.code] = member.name
mapping[member.abbr] = member.name
return mapping
# have str() print just the country name
def __str__(self):
return self.country_name
Run Code Online (Sandbox Code Playgroud)
虽然我包含了该choices方法,但您可能不需要它:
>>> Country('AF')
<Country.AF: ('AF', 4, 'Afghanistan')>
>>> Country(4)
<Country.AF: ('AF', 4, 'Afghanistan')>
>>> Country('Afghanistan')
<Country.AF: ('AF', 4, 'Afghanistan')>
Run Code Online (Sandbox Code Playgroud)
1声明:我是Python stdlibEnum、enum34backport和Advanced Enumeration ( aenum)库的作者 。
2这需要aenum 2.0.5+.
这个怎么样?
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)
Run Code Online (Sandbox Code Playgroud)
[...data[i]... for i in range(len(data))]为[...x... for x in data]; 您可以data在不使用索引的情况下迭代序列(列表,在代码中)。CountryCode.attr = ...;而不是混合CountryCode.attr = ...和setattr(CountryCode, 'attr', ...)。