在本文中, Nick
Coghlan讨论了PEP
435Enum
类型的
一些设计决策,以及如何EnumMeta
将其子类化以提供不同的Enum
体验。
但是,我给出的建议(我是stdlib的主要Enum
作者)关于使用元类的建议是,在没有充分好的理由的情况下不应该这样做-
例如,无法使用类装饰器或专用工具来完成所需的工作隐藏任何丑陋的功能;而在我自己的工作,我已经能够做到我需要什么简单的使用__new__
,__init__
在创建时,和/或正常类/实例方法Enum
类:
Enum
具有属性
处理失踪成员
不是Enum
成员的类常量
考虑到所有这些,我什么时候需要摆弄EnumMeta
自己?
首先,查看不进行子类化时所需的代码EnumMeta
:
stdlib方式
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
Country = BaseCountry(
'Country',
[(rec['alpha-2'], rec) for rec in json.load(open('slim-2.json'))],
)
该aenum
方法 1 2
from aenum import Enum, MultiValue
import json
class Country(Enum, init='abbr code country_name', settings=MultiValue):
_ignore_ = 'country this' # 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'],
)
# have str() print just the country name
def __str__(self):
return self.country_name
上面的代码适合一次性枚举-但是如果从JSON文件创建枚举对您来说很普遍怎么办?想象一下您是否可以这样做:
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),
}
如你看到的:
_file
是要使用的json文件的名称_name
是该名称应使用的路径_value
是将路径映射到值3的字典_init_
指定不同值组件的属性名称(如果使用aenum
)JSON数据摘自https://github.com/lukes/ISO-3166-Countries-with-Regional-Codes-
以下
是简短摘录:
[{“ name”:“ Afghanistan”,“ alpha-2”:“ AF”,“国家/地区代码”:“ 004”},
{“ name”:“ÅlandIslands”,“ alpha-2”:“ AX”,“国家/地区代码”:“ 248”},
{“名称”:“阿尔巴尼亚”,“ alpha-2”:“ AL”,“国家代码”:“ 008”},
{“名称”:“阿尔及利亚”,“ alpha-2”:“ DZ”,“国家/地区代码”:“ 012”}]
这是JSONEnumMeta
课程:
class JSONEnumMeta(EnumMeta):
@classmethod
def __prepare__(metacls, cls, bases, **kwds):
# return a standard dictionary for the initial processing
return {}
def __init__(cls, *args , **kwds):
super(JSONEnumMeta, cls).__init__(*args)
def __new__(metacls, cls, bases, clsdict, **kwds):
import json
members = []
missing = [
name
for name in ('_file', '_name', '_value')
if name not in clsdict
]
if len(missing) in (1, 2):
# all three must be present or absent
raise TypeError('missing required settings: %r' % (missing, ))
if not missing:
# process
name_spec = clsdict.pop('_name')
if not isinstance(name_spec, (tuple, list)):
name_spec = (name_spec, )
value_spec = clsdict.pop('_value')
file = clsdict.pop('_file')
with open(file) as f:
json_data = json.load(f)
for data in json_data:
values = []
name = data[name_spec[0]]
for piece in name_spec[1:]:
name = name[piece]
for order, (value_path, func) in sorted(value_spec.items()):
if not isinstance(value_path, (list, tuple)):
value_path = (value_path, )
value = data[value_path[0]]
for piece in value_path[1:]:
value = value[piece]
if func is not None:
value = func(value)
values.append(value)
values = tuple(values)
members.append(
(name, values)
)
# get the real EnumDict
enum_dict = super(JSONEnumMeta, metacls).__prepare__(cls, bases, **kwds)
# transfer the original dict content, _items first
items = list(clsdict.items())
items.sort(key=lambda p: (0 if p[0][0] == '_' else 1, p))
for name, value in items:
enum_dict[name] = value
# add the members
for name, value in members:
enum_dict[name] = value
return super(JSONEnumMeta, metacls).__new__(metacls, cls, bases, enum_dict, **kwds)
# for use with both Python 2/3
JSONEnum = JSONEnumMeta('JsonEnum', (Enum, ), {})
一些注意事项:
JSONEnumMeta.__prepare__
返回正常 dict
EnumMeta.__prepare__
用于获取的实例_EnumDict
-这是获取实例的正确方法
带下划线的键将被传递给实数_EnumDict
优先,因为在处理枚举成员时可能需要它们
枚举成员的顺序与文件中的顺序相同
1披露:我是Python
stdlibEnum
,enum34
backport和Advanced
Enumeration(aenum
) 库的作者。
2这需要aenum 2.0.5+
。
3键是数字键,可以在需要多个值时按顺序保留多个值Enum
。
问题内容: 流式XML解析器(例如SAX和StAX)比构建像DOM解析器之类的树结构的解析器更快,内存效率更高。SAX是推送分析器,这意味着它是观察者模式(也称为侦听器模式)的实例。SAX首先出现,然后是StAX- 拉式解析器,这意味着它基本上像迭代器一样工作。 您可以找到在任何地方都偏爱StAX而不是SAX的原因,但是通常可以归结为:“更易于使用”。 在JAXP上的Java教程中,StAX被模糊
问题内容: 我是一名C ++程序员,偶尔使用MySQL处理数据库,但是我的SQL知识非常有限。但是,我当然愿意改变这一点。 目前,我正尝试仅通过SQL查询对数据库中的数据进行分析(!)。但是我将放弃,而是将数据导入C 并使用C 代码进行分析。 我已经与同事讨论了这一点,他们也促使我使用C ++,他说SQL并不是用于复杂的分析,而是主要用于导入(从现有表中)和导出(到新表中)数据,还有更多内容。例如
问题内容: 编码要发送到Web服务器的查询字符串时-您何时使用以及何时使用或: 使用转义: 要么 使用encodeURI()/ encodeURIComponent() 问题答案: escape() 不要使用它! 在B.2.1.2节中定义了转义,并且附件B的引言中指出: …本附件中指定的所有语言功能和行为均具有一个或多个不良特征,在没有遗留用法的情况下,将从本规范中删除。… …程序员不应该使用或编
问题内容: 偏重于继承而不是继承 是非常流行的短语。我读了几篇文章,最后每篇文章都说 当类之间存在纯IS-A关系时,请使用继承。 本文中的一个示例: 在 Apple 和 Fruit 之间存在明显的IS-A关系,即Apple IS-A Fruit,但作者也将其显示为Apple HAS-A Fruit(组成),以显示通过继承实现时的陷阱。 我在这里变得有些困惑,声明的含义是什么 当类之间存在纯IS-A
问题内容: 实际上,这是一个类似的话题,几乎没有实用价值。据我了解,原语性能更好,除需要与对象相关的功能(例如检查)外,应在所有地方使用。对? 问题答案: 别忘了,由于为每次装箱而创建一个新的包装程序都是非常昂贵的,尤其是考虑到通常在一种方法的单个作用域中使用它,因此自动装箱将使用一组通用包装程序。 这实际上是flyweight设计模式的一种实现。当对一个众所周知的值进行装箱时,而不是创建一个新的
问题内容: 我知道他们两个都禁用了Nagle的算法。 我什么时候应该/不应该使用它们中的每一个? 问题答案: 首先,不是所有人都禁用Nagle的算法。 Nagle的算法用于减少有线中更多的小型网络数据包。该算法是:如果数据小于限制(通常是MSS),请等待直到收到先前发送的数据包的ACK,同时累积用户的数据。然后发送累积的数据。 这将对telnet等应用程序有所帮助。但是,在发送流数据时,等待A