程式扎記: [Python 文章收集] Yet another lightweight Enum for Python 2.7

標籤

2016年8月23日 星期二

[Python 文章收集] Yet another lightweight Enum for Python 2.7

Source From Here 
Preface 
I'm trying to develop a lightweight enum for Python 2.7. This question is downstream of the SO question here; for context, a streamlined version of the bulleted addendum to that question is replicated below (My desired feature set is): 
* Only having to type the enum name (or value) once in the source definition.
* Valid enum values exposed for IDE autocomplete.
* Enum values stored internally as comprehensible strings.
* Straightforward membership testing using native Python in.
* Ability to import individual enum subclasses via, say, from .enums import myEnum, to avoid cluttering the local namespace with other enums I don't care about.
* I would rather avoid introducing an additional package dependency by using enum34, as I don't (think I) need the feature set.
* Clean, readable definition of enum values.

How-To 
To note, every form of dynamic namespace construction I've tried, in efforts to accomplish #1, has broken #2. I'm pretty sure at this point they're mutually exclusive. In any event, my current solution goes as follows, defining an enum superclass with a metaclassed type with an iterator that returns all members with string content identical to the respective member names: 
- EnumBase.py 
  1. class SuperEnum(object):  
  2.     class __metaclass__(type):  
  3.         def __iter__(self):  
  4.             for item in self.__dict__:  
  5.                 if item == self.__dict__[item]:  
  6.                     yield item  
  7.   
  8. class EnumMeta(type):  
  9.     def __new__(metaClz, enumClzName, supers, attrs):  
  10.         return type(enumClzName, supers, attrs)  
  11.     def __init__(self, clzName, supers, attrs):  
  12.         pass  
  13.   
  14. def GenEnum(clzName, enum_values):  
  15.     EnumClz = EnumMeta(clzName, (SuperEnum,), enum_values)  
  16.     return EnumClz  
Each enum is then subclassed from this SuperEnum, e.g.: 
  1. class MyEnum(SuperEnum):  
  2.     A = "A"  
  3.     B = "B"  
  4.     C = "C"  
The usage is working just as I want (except of course for #1), including for the IDE autocomplete of #2: 
>>> from EnumBase import *
>>> MyEnum = GenEnum('MyEnum', {"A":"A", "B":"B", "C":"C"})
>>> MyEnum.A
'A'
>>> 'A' in MyEnum
True
>>> 'E' in MyEnum
False
>>> hasattr(MyEnum, 'A')
True
>>> hasattr(MyEnum, 'E')
False
>>> C = MyEnum.C
>>> C in MyEnum
True

This construction is far more concise than anything I'd set up around the time I posted the above-linked SO question, so the need to type the value name twice in the enum class definition isn't terribly bothersome. I'm still interested to know if there's any way to make #1 and #2 play nice together, though. 

More generally: what might the weaknesses of this construction be? For my application, performance is of minor concern. There's always the possibility of value collisions, as described here, but using strings as the values dramatically reduces the likelihood. Security issues? Compatibility problems of some kind? 

Supplement 
[ Python 文章收集 ] 深刻理解 Python 中的元類 (metaclass)

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!