Python独自のEnum最適化
3887 ワード
Python公式のEnum使用値のため、データベースなどを書く際に加算する必要があります.valueは、問題を起こしやすいのでenumを書き直しました.
いくつかの互換性コードがありますが、削除できます.ここでは最適化しません.
いくつかの互換性コードがありますが、削除できます.ここでは最適化しません.
# coding: utf-8
"""
Enum , python enum34 Enum、IntEnum .value , bug, ,Enum
In , , Enum。 , Enum34 , __choices__ , , 。
enum34 , 。
class Example(Enum):
a = 1
b = 2
__choices__ = (
(a, u' a'),
(b, u' b'),
)
>> Example['a'] #
Out: 1
>> Example[1] #
Out: 1
>> c = Example[3]
Out: ValueError: 3
>> c = Example['c']
Out: KeyError: c
>> a1 = Example[1]
>> print a1
Out: 1
>> a1.label
Out: u' a'
>> a1.name
Out: a
"""
from __future__ import unicode_literals
class NewInt(int):
""" int , label,value """
class NewStr(str):
""" str , label,value """
class NewUnicode(unicode):
""" unicode , label,value """
# from enum import Enum
class EnumMeta(type):
__choices__ = ()
_enum_type = NewInt
def __new__(mcs, *args, **kwargs):
obj = type.__new__(mcs, *args, **kwargs)
obj._value_to_label = dict(obj.__choices__) # label
obj._keys, obj._values = [], []
for key, value in obj.__dict__.items():
if not key.startswith('_'):
if isinstance(value, (int, basestring)):
val = obj._enum_type(value)
val.name = key
val.value = value # todo wangtao .value ,
val.label = obj._value_to_label.get(val) or key
setattr(obj, key, val)
obj._keys.append(key)
obj._values.append(val)
if len(set(obj._keys)) != len(set(obj._values)): #
raise ValueError('duplicate value')
return obj
def __getitem__(self, key):
""" name value """
for val in self._values:
if val == key:
return val
if key in self._keys:
return getattr(self, key, None)
raise KeyError(key)
def __setattr__(cls, key, value):
if not key.startswith('_') and key in cls._keys:
raise AttributeError('Cannot reassign members')
return super(EnumMeta, cls).__setattr__(key, value)
class EnumMixin(object):
__choices__ = ()
@classmethod
def to_dict(cls):
if not getattr(cls, '_to_dict', None):
cls._to_dict = dict((x.name, x.value) for x in cls._values)
return cls._to_dict
@classmethod
def label_items(cls):
return cls.__choices__
@classmethod
def get_choices(cls):
return cls.__choices__
@classmethod
def get_display_name(cls, value):
return cls[value].label
@classmethod
def all_elements(cls):
return cls._values
# Enum.name('name') / Enum.value(1) Enum['name'] , Enum[1]
@classmethod
def name(cls, name):
res = getattr(cls, name)
if res is None:
raise KeyError(name)
return res
@classmethod
def value(cls, value):
for val in cls._values:
if val == value:
return val
else:
raise ValueError(value)
def __new__(cls, enum_value):
return cls[enum_value]
class Enum(EnumMixin):
__metaclass__ = EnumMeta
_enum_type = NewStr
class IntEnum(EnumMixin):
__metaclass__ = EnumMeta
_enum_type = NewInt
class UnicodeEnum(EnumMixin):
__metaclass__ = EnumMeta
_enum_type = NewUnicode