AttributeError: module 'enum' has no attribute 'IntFlag'
$ /Library/Frameworks/Python.framework/Versions/3.6/bin/python3
Failed to import the site module
Traceback(most recent call last):File"/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site.py", line 544,in<module>
main()File"/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site.py", line 530,in main
known_paths = addusersitepackages(known_paths)File"/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site.py", line 282,in addusersitepackages
user_site = getusersitepackages()File"/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site.py", line 258,in getusersitepackages
user_base = getuserbase()# this will also set USER_BASE File"/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site.py", line 248,in getuserbase
USER_BASE = get_config_var('userbase')File"/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/sysconfig.py", line 601,in get_config_var
return get_config_vars().get(name)File"/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/sysconfig.py", line 580,in get_config_vars
import _osx_support
File"/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/_osx_support.py", line 4,in<module>import re
File"/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/re.py", line 142,in<module>classRegexFlag(enum.IntFlag):AttributeError: module 'enum' has no attribute 'IntFlag'
When I attempt to run the Console(or run anything with Python3), this error is thrown:
AttributeError: module 'enum' has no attribute 'IntFlag'
$ /Library/Frameworks/Python.framework/Versions/3.6/bin/python3
Failed to import the site module
Traceback (most recent call last):
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site.py", line 544, in <module>
main()
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site.py", line 530, in main
known_paths = addusersitepackages(known_paths)
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site.py", line 282, in addusersitepackages
user_site = getusersitepackages()
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site.py", line 258, in getusersitepackages
user_base = getuserbase() # this will also set USER_BASE
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site.py", line 248, in getuserbase
USER_BASE = get_config_var('userbase')
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/sysconfig.py", line 601, in get_config_var
return get_config_vars().get(name)
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/sysconfig.py", line 580, in get_config_vars
import _osx_support
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/_osx_support.py", line 4, in <module>
import re
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/re.py", line 142, in <module>
class RegexFlag(enum.IntFlag):
AttributeError: module 'enum' has no attribute 'IntFlag'
The class IntFlag exists within enum.py. So, why is the AttributeError being thrown?
It’s because your enum is not the standard library enum module. You probably have the package enum34 installed.
One way check if this is the case is to inspect the property enum.__file__
import enum
print(enum.__file__)
# standard library location should be something like
# /usr/local/lib/python3.6/enum.py
Since python 3.6 the enum34 library is no longer compatible with the standard library. The library is also unnecessary, so you can simply uninstall it.
pip uninstall -y enum34
If you need the code to run on python versions both <=3.4 and >3.4, you can try having enum-compat as a requirement. It only installs enum34 for older versions of python without the standard library enum.
For me this error occured after installing of gcloud component app-engine-python in order to integrate into pycharm. Uninstalling the module helped, even if pycharm is now not uploading to app-engine.
If anyone coming here because of getting this error while running a google app engine Python 3.7 standard environment project in PyCharm then all you need to do is
Make sure the configuration to run is for Flask, not Google App Engine configuration.
Then disable Google App Engine support under Preferences >> Languages & Framework >> Google App Engine
The overall goal is that your app should be fully portable and run in any standard Python environment. You write a standard Python app, not an App Engine Python app. As part of this shift, you are no longer required to use proprietary App Engine APIs and services for your app’s core functionality. At this time, App Engine APIs are not available in the Python 3.7 runtime.
I guess when we create a python 3.7 project in PyCharm as a Google app engine project it still tries to do the same way it does for a python2.7 app
Håken Lid’s answer helped solved my problem (thanks!) , in my case present in Python3.7 running Flask in a Docker container (FROM tiangolo/uwsgi-nginx-flask:python3.7-alpine3.7).
In my case, enum34 was being installed by another library (pip install smartsheet-python-sdk).
For those coming with a similar Docker container problem, here is my final Dockerfile (stripped to the relevant lines):
FROM tiangolo/uwsgi-nginx-flask:python3.7-alpine3.7
...
RUN pip install -r requirements.txt
RUN pip uninstall -y enum34
...
AttributeError: module ‘enum’ has no attribute ‘IntFlag’
simply first i run the command:
unset PYTHONPATH
and then run my desired command then got success in that.
回答 9
使用pip install <required-library> --ignore-installed enum34
安装所需的库后,在构建过程中查找警告。我收到这样的错误: Using legacy setup.py install for future, since package 'wheel' is not installed ERROR: pyejabberd 0.2.11 has requirement enum34==1.1.2, but you'll have enum34 1.1.10 which is incompatible.
I did by using pip install <required-library> --ignore-installed enum34
Once your required library is installed, look for warnings during the build.
I got an Error like this: Using legacy setup.py install for future, since package 'wheel' is not installed ERROR: pyejabberd 0.2.11 has requirement enum34==1.1.2, but you'll have enum34 1.1.10 which is incompatible.
To fix this issue now run the command: pip freeze | grep enum34. This will give you the version of the installed enum34. Now uninstall it by pip uninstall enum34 and reinstall the required version as pip install "enum34==1.1.20"
I have Python 2 and Python 3 installed on my computer. For some strange reason I have in the sys.path of Python 3 also a path to the sitepackage library directory of Python2 when the re module is called. If I run Python 3 and import enum and print(enum.__file__) the system does not show this Python 2 path to site-packages. So a very rough and dirty hack is, to directly modify the module in which enum is imported (follow the traceback paths) and insert the following code just before importing enum:
import sys
for i, p in enumerate(sys.path):
if "python27" in p.lower() or "python2.7" in p.lower(): sys.path.pop(i)
import enum
I was able to fix this by adding enum34 = “==1.1.8” to pyproject.toml.
Apparently enum34 had a feature in v1.1.8 that avoided this error, but
this regressed in v1.1.9+. This is just a workaround though. The
better solution would be for packages to use environment markers so
you don’t have to install enum34 at all unless needed.
Even I had this issue while running python -m grpc_tools.protoc –version
Had to set the PYTHONPATH till site-packages and shutdown all the command prompt windows and it worked. Hope it helps for gRPC users.
Traceback(most recent call last):File"/usr/lib/python2.7/runpy.py", line 174,in _run_module_as_main
"__main__", fname, loader, pkg_name)File"/usr/lib/python2.7/runpy.py", line 72,in _run_code
exec code in run_globals
File"/home/hu-mka/.local/lib/python2.7/site-packages/ipykernel_launcher.py", line 15,in<module>from ipykernel import kernelapp as app
File"/home/hu-mka/.local/lib/python2.7/site-packages/ipykernel/__init__.py", line 2,in<module>from.connect import*File"/home/hu-mka/.local/lib/python2.7/site-packages/ipykernel/connect.py", line 13,in<module>fromIPython.core.profiledir importProfileDirFile"/home/hu-mka/.local/lib/python2.7/site-packages/IPython/__init__.py", line 48,in<module>from.core.application importApplicationFile"/home/hu-mka/.local/lib/python2.7/site-packages/IPython/core/application.py", line 23,in<module>from traitlets.config.application importApplication, catch_config_error
File"/home/hu-mka/.local/lib/python2.7/site-packages/traitlets/__init__.py", line 1,in<module>from.traitlets import*File"/home/hu-mka/.local/lib/python2.7/site-packages/traitlets/traitlets.py", line 49,in<module>import enum
ImportError:No module named enum
I had this problem in ubuntu20.04 in jupyterlab in my virtual env kernel with python3.8 and tensorflow 2.2.0. Error message was
Traceback (most recent call last):
File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/home/hu-mka/.local/lib/python2.7/site-packages/ipykernel_launcher.py", line 15, in <module>
from ipykernel import kernelapp as app
File "/home/hu-mka/.local/lib/python2.7/site-packages/ipykernel/__init__.py", line 2, in <module>
from .connect import *
File "/home/hu-mka/.local/lib/python2.7/site-packages/ipykernel/connect.py", line 13, in <module>
from IPython.core.profiledir import ProfileDir
File "/home/hu-mka/.local/lib/python2.7/site-packages/IPython/__init__.py", line 48, in <module>
from .core.application import Application
File "/home/hu-mka/.local/lib/python2.7/site-packages/IPython/core/application.py", line 23, in <module>
from traitlets.config.application import Application, catch_config_error
File "/home/hu-mka/.local/lib/python2.7/site-packages/traitlets/__init__.py", line 1, in <module>
from .traitlets import *
File "/home/hu-mka/.local/lib/python2.7/site-packages/traitlets/traitlets.py", line 49, in <module>
import enum
ImportError: No module named enum
problem was that in symbolic link in /usr/bin/python was pointing to python2. Solution:
cd /usr/bin/
sudo ln -sf python3 python
Hopefully Python 2 usage will drop off completely soon.
If anyone is having this problem when trying to run Jupyter kernel from a virtualenv, just add correct PYTHONPATH to kernel.json of your virtualenv kernel (Python 3 in example):
Using the new Enum feature (via backport enum34) with python 2.7.6.
Given the following definition, how can I convert an int to the corresponding Enum value?
from enum import Enum
class Fruit(Enum):
Apple = 4
Orange = 5
Pear = 6
I know I can hand craft a series of if-statements to do the conversion but is there an easy pythonic way to convert? Basically, I’d like a function ConvertIntToFruit(int) that returns an enum value.
My use case is I have a csv file of records where I’m reading each record into an object. One of the file fields is an integer field that represents an enumeration. As I’m populating the object I’d like to convert that integer field from the file into the corresponding Enum value in the object.
回答 0
您“打电话”Enum上课:
Fruit(5)
轮到5为Fruit.Orange:
>>> from enum import Enum
>>> classFruit(Enum):... Apple = 4... Orange = 5... Pear = 6... >>> Fruit(5)
<Fruit.Orange: 5>
Sometimes it’s useful to access members in enumerations
programmatically (i.e. situations where Color.red won’t do because the
exact color is not known at program-writing time). Enum allows such
access:
The failure throws an exception as would be expected.
A more robust version:
#!/usr/bin/env python3
class EnumDemo():
enumeration = (
'ENUM_ZERO', # 0.
'ENUM_ONE', # 1.
'ENUM_TWO', # 2.
'ENUM_THREE', # 3.
'ENUM_INVALID' # 4.
)
def name(self, val):
try:
name = self.enumeration[val]
except IndexError:
# Always return last tuple.
name = self.enumeration[len(self.enumeration) - 1]
return name
def number(self, val):
try:
index = self.enumeration.index(val)
except (TypeError, ValueError):
# Always return last tuple.
index = (len(self.enumeration) - 1)
return index
#endclass.
print('Passes')
print('1) %d'%(EnumDemo().number('ENUM_TWO')))
print('2) %s'%(EnumDemo().number('ENUM_TWO')))
print('3) %s'%(EnumDemo().name(1)))
print('4) %s'%(EnumDemo().enumeration[1]))
print()
print('Fails')
print('1) %d'%(EnumDemo().number('ENUM_THREEa')))
print('2) %s'%(EnumDemo().number('ENUM_THREEa')))
print('3) %s'%(EnumDemo().name(11)))
print('4) %s'%(EnumDemo().enumeration[-1]))
When not used correctly this avoids creating an exception and, instead, passes back a fault indication. A more Pythonic way to do this would be to pass back “None” but my particular application uses the text directly.
If you want to encode an arbitrary enum.Enum member to JSON and then decode
it as the same enum member (rather than simply the enum member’s value attribute), you can do so by writing a custom JSONEncoder class, and a decoding function to pass as the object_hook argument to json.load() or json.loads():
PUBLIC_ENUMS = {
'Status': Status,
# ...
}
class EnumEncoder(json.JSONEncoder):
def default(self, obj):
if type(obj) in PUBLIC_ENUMS.values():
return {"__enum__": str(obj)}
return json.JSONEncoder.default(self, obj)
def as_enum(d):
if "__enum__" in d:
name, member = d["__enum__"].split(".")
return getattr(PUBLIC_ENUMS[name], member)
else:
return d
The as_enum function relies on the JSON having been encoded using EnumEncoder, or something which behaves identically to it.
The restriction to members of PUBLIC_ENUMS is necessary to avoid a maliciously crafted text being used to, for example, trick calling code into saving private information (e.g. a secret key used by the application) to an unrelated database field, from where it could then be exposed (see http://chat.stackoverflow.com/transcript/message/35999686#35999686).
I know this is old but I feel this will help people. I just went through this exact problem and discovered if you’re using string enums, declaring your enums as a subclass of str works well for almost all situations:
import json
from enum import Enum
class LogLevel(str, Enum):
DEBUG = 'DEBUG'
INFO = 'INFO'
print(LogLevel.DEBUG)
print(json.dumps(LogLevel.DEBUG))
print(json.loads('"DEBUG"'))
print(LogLevel('DEBUG'))
Will output:
LogLevel.DEBUG
"DEBUG"
DEBUG
LogLevel.DEBUG
As you can see, loading the JSON outputs the string DEBUG but it is easily castable back into a LogLevel object. A good option if you don’t want to create a custom JSONEncoder.
The correct answer depends on what you intend to do with the serialized version.
If you are going to unserialize back into Python, see Zero’s answer.
If your serialized version is going to another language then you probably want to use an IntEnum instead, which is automatically serialized as the corresponding integer:
from enum import IntEnum
import json
class Status(IntEnum):
success = 0
failure = 1
json.dumps(Status.success)
class Status(Enum):
success = 0
def __json__(self):
return self.value
Didn’t have to change anything else. Obviously, you’ll only get the value out of this and will need to do some other work if you want to convert the serialized value back into the enum later.
I wonder what’s the correct way of converting (deserializing) a string to a Python’s Enum class. Seems like getattr(YourEnumType, str) does the job, but I’m not sure if it’s safe enough.
Just to be more specific, I would like to convert a 'debug'string to an Enum object like this:
Another alternative (especially useful if your strings don’t map 1-1 to your enum cases) is to add a staticmethod to your Enum, e.g.:
class QuestionType(enum.Enum):
MULTI_SELECT = "multi"
SINGLE_SELECT = "single"
@staticmethod
def from_str(label):
if label in ('single', 'singleSelect'):
return QuestionType.SINGLE_SELECT
elif label in ('multi', 'multiSelect'):
return QuestionType.MULTI_SELECT
else:
raise NotImplementedError
Then you can do question_type = QuestionType.from_str('singleSelect')
回答 2
def custom_enum(typename, items_dict):
class_definition ="""
from enum import Enum
class {}(Enum):
{}""".format(typename,'\n '.join(['{} = {}'.format(k, v)for k, v in items_dict.items()]))
namespace = dict(__name__='enum_%s'% typename)exec(class_definition, namespace)
result = namespace[typename]
result._source = class_definition
return result
MyEnum= custom_enum('MyEnum',{'a':123,'b':321})print(MyEnum.a,MyEnum.b)
还是需要将字符串转换为已知的 Enum?
classMyEnum(Enum):
a ='aaa'
b =123print(MyEnum('aaa'),MyEnum(123))
要么:
classBuildType(Enum):
debug =200
release =400print(BuildType.__dict__['debug'])print(eval('BuildType.debug'))print(type(eval('BuildType.debug')))print(eval(BuildType.__name__ +'.debug'))# for work with code refactoring
def custom_enum(typename, items_dict):
class_definition = """
from enum import Enum
class {}(Enum):
{}""".format(typename, '\n '.join(['{} = {}'.format(k, v) for k, v in items_dict.items()]))
namespace = dict(__name__='enum_%s' % typename)
exec(class_definition, namespace)
result = namespace[typename]
result._source = class_definition
return result
MyEnum = custom_enum('MyEnum', {'a': 123, 'b': 321})
print(MyEnum.a, MyEnum.b)
Or you need to convert string to known Enum?
class MyEnum(Enum):
a = 'aaa'
b = 123
print(MyEnum('aaa'), MyEnum(123))
Or:
class BuildType(Enum):
debug = 200
release = 400
print(BuildType.__dict__['debug'])
print(eval('BuildType.debug'))
print(type(eval('BuildType.debug')))
print(eval(BuildType.__name__ + '.debug')) # for work with code refactoring
回答 3
我的类Java解决方案。希望它可以帮助某人…
from enum importEnum, auto
classSignInMethod(Enum):
EMAIL = auto(),
GOOGLE = auto()@staticmethoddef value_of(value)->Enum:for m, mm inSignInMethod.__members__.items():if m == value.upper():return mm
sim =SignInMethod.value_of('EMAIL')print("""TEST
1). {0}
2). {1}
3). {2}
""".format(sim, sim.name, isinstance(sim,SignInMethod)))
My Java-like solution to the problem. Hope it helps someone…
from enum import Enum, auto
class SignInMethod(Enum):
EMAIL = auto(),
GOOGLE = auto()
@staticmethod
def value_of(value) -> Enum:
for m, mm in SignInMethod.__members__.items():
if m == value.upper():
return mm
sim = SignInMethod.value_of('EMAIL')
print("""TEST
1). {0}
2). {1}
3). {2}
""".format(sim, sim.name, isinstance(sim, SignInMethod)))
from enum importEnum# for enum34, or the stdlib version# from aenum import Enum # for the aenum versionAnimal=Enum('Animal','ant bee cat dog')Animal.ant # returns <Animal.ant: 1>Animal['ant']# returns <Animal.ant: 1> (string lookup)Animal.ant.name # returns 'ant' (inverse lookup)
For more advanced Enum techniques try the aenum library (2.7, 3.3+, same author as enum34. Code is not perfectly compatible between py2 and py3, e.g. you’ll need __order__ in python 2).
To use enum34, do $ pip install enum34
To use aenum, do $ pip install aenum
Installing enum (no numbers) will install a completely different and incompatible version.
from enum import Enum # for enum34, or the stdlib version
# from aenum import Enum # for the aenum version
Animal = Enum('Animal', 'ant bee cat dog')
Animal.ant # returns <Animal.ant: 1>
Animal['ant'] # returns <Animal.ant: 1> (string lookup)
Animal.ant.name # returns 'ant' (inverse lookup)
or equivalently:
class Animal(Enum):
ant = 1
bee = 2
cat = 3
dog = 4
In earlier versions, one way of accomplishing enums is:
Support for converting the values back to names can be added this way:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
reverse = dict((value, key) for key, value in enums.iteritems())
enums['reverse_mapping'] = reverse
return type('Enum', (), enums)
This overwrites anything with that name, but it is useful for rendering your enums in output. It will throw KeyError if the reverse mapping doesn’t exist. With the first example:
Before PEP 435, Python didn’t have an equivalent but you could implement your own.
Myself, I like keeping it simple (I’ve seen some horribly complex examples on the net), something like this …
class Animal:
DOG = 1
CAT = 2
x = Animal.DOG
In Python 3.4 (PEP 435), you can make Enum the base class. This gets you a little bit of extra functionality, described in the PEP. For example, enum members are distinct from integers, and they are composed of a name and a value.
class Animal(Enum):
DOG = 1
CAT = 2
print(Animal.DOG)
# <Animal.DOG: 1>
print(Animal.DOG.value)
# 1
print(Animal.DOG.name)
# "DOG"
If you don’t want to type the values, use the following shortcut:
class Animal(Enum):
DOG, CAT = range(2)
Enum implementations can be converted to lists and are iterable. The order of its members is the declaration order and has nothing to do with their values. For example:
class Animal(Enum):
DOG = 1
CAT = 2
COW = 0
list(Animal)
# [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.COW: 0>]
[animal.value for animal in Animal]
# [1, 2, 0]
Animal.CAT in Animal
# True
回答 2
这是一个实现:
classEnum(set):def __getattr__(self, name):if name in self:return nameraiseAttributeError
If you need the numeric values, here’s the quickest way:
dog, cat, rabbit = range(3)
In Python 3.x you can also add a starred placeholder at the end, which will soak up all the remaining values of the range in case you don’t mind wasting memory and cannot count:
The best solution for you would depend on what you require from your fakeenum.
Simple enum:
If you need the enum as only a list of names identifying different items, the solution by Mark Harrison (above) is great:
Pen, Pencil, Eraser = range(0, 3)
Using a range also allows you to set any starting value:
Pen, Pencil, Eraser = range(9, 12)
In addition to the above, if you also require that the items belong to a container of some sort, then embed them in a class:
class Stationery:
Pen, Pencil, Eraser = range(0, 3)
To use the enum item, you would now need to use the container name and the item name:
stype = Stationery.Pen
Complex enum:
For long lists of enum or more complicated uses of enum, these solutions will not suffice. You could look to the recipe by Will Ware for Simulating Enumerations in Python published in the Python Cookbook. An online version of that is available here.
The typesafe enum pattern which was used in Java pre-JDK 5 has a
number of advantages. Much like in Alexandru’s answer, you create a
class and class level fields are the enum values; however, the enum
values are instances of the class rather than small integers. This has
the advantage that your enum values don’t inadvertently compare equal
to small integers, you can control how they’re printed, add arbitrary
methods if that’s useful and make assertions using isinstance:
class Animal:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def __repr__(self):
return "<Animal: %s>" % self
Animal.DOG = Animal("dog")
Animal.CAT = Animal("cat")
>>> x = Animal.DOG
>>> x
<Animal: dog>
>>> x == 1
False
A recent thread on python-dev pointed out there are a couple of enum libraries in the wild, including:
>>>State=Enum(['Unclaimed','Claimed'])>>>State.Claimed1>>>State[1]'Claimed'>>>State('Unclaimed','Claimed')>>> range(len(State))[0,1]>>>[(k,State[k])for k in range(len(State))][(0,'Unclaimed'),(1,'Claimed')]>>>[(k, getattr(State, k))for k inState][('Unclaimed',0),('Claimed',1)]
Python doesn’t have a built-in equivalent to enum, and other answers have ideas for implementing your own (you may also be interested in the over the top version in the Python cookbook).
However, in situations where an enum would be called for in C, I usually end up just using simple strings: because of the way objects/attributes are implemented, (C)Python is optimized to work very fast with short strings anyway, so there wouldn’t really be any performance benefit to using integers. To guard against typos / invalid values you can insert checks in selected places.
On 2013-05-10, Guido agreed to accept PEP 435 into the Python 3.4 standard library. This means that Python finally has builtin support for enumerations!
There is a backport available for Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4. It’s on Pypi as enum34.
Declaration:
>>> from enum import Enum
>>> class Color(Enum):
... red = 1
... green = 2
... blue = 3
class Animal:
class Dog: pass
class Cat: pass
x = Animal.Dog
It’s more bug-proof than using integers since you don’t have to worry about ensuring that the integers are unique (e.g. if you said Dog = 1 and Cat = 1 you’d be screwed).
It’s more bug-proof than using strings since you don’t have to worry about typos (e.g.
x == “catt” fails silently, but x == Animal.Catt is a runtime exception).
回答 11
def M_add_class_attribs(attribs):def foo(name, bases, dict_):for v, k in attribs:
dict_[k]= v
return type(name, bases, dict_)return foo
def enum(*names):classFoo(object):
__metaclass__ = M_add_class_attribs(enumerate(names))def __setattr__(self, name, value):# this makes it read-onlyraiseNotImplementedErrorreturnFoo()
def M_add_class_attribs(attribs):
def foo(name, bases, dict_):
for v, k in attribs:
dict_[k] = v
return type(name, bases, dict_)
return foo
def enum(*names):
class Foo(object):
__metaclass__ = M_add_class_attribs(enumerate(names))
def __setattr__(self, name, value): # this makes it read-only
raise NotImplementedError
return Foo()
Hmmm… I suppose the closest thing to an enum would be a dictionary, defined either like this:
months = {
'January': 1,
'February': 2,
...
}
or
months = dict(
January=1,
February=2,
...
)
Then, you can use the symbolic name for the constants like this:
mymonth = months['January']
There are other options, like a list of tuples, or a tuple of tuples, but the dictionary is the only one that provides you with a “symbolic” (constant string) way to access the
value.
Edit: I like Alexandru’s answer too!
回答 13
另一个非常简单的Python枚举实现,使用namedtuple:
from collections import namedtuple
def enum(*keys):return namedtuple('Enum', keys)(*keys)MyEnum= enum('FOO','BAR','BAZ')
或者,
# With sequential number valuesdef enum(*keys):return namedtuple('Enum', keys)(*range(len(keys)))# From a dict / keyword argsdef enum(**kwargs):return namedtuple('Enum', kwargs.keys())(*kwargs.values())
就像上面子类的方法一样set,这允许:
'FOO'inMyEnum
other =MyEnum.FOO
assert other ==MyEnum.FOO
Enumerations are created using the class syntax, which makes them easy
to read and write. An alternative creation method is described in
Functional API. To define an enumeration, subclass Enum as follows:
from enum import Enum
class Color(Enum):
red = 1
green = 2
blue = 3
回答 15
我用什么:
classEnum(object):def __init__(self, names, separator=None):
self.names = names.split(separator)for value, name in enumerate(self.names):
setattr(self, name.upper(), value)def tuples(self):return tuple(enumerate(self.names))
如何使用:
>>> state =Enum('draft published retracted')>>> state.DRAFT
0>>> state.RETRACTED
2>>> state.FOO
Traceback(most recent call last):File"<stdin>", line 1,in<module>AttributeError:'Enum' object has no attribute 'FOO'>>> state.tuples()((0,'draft'),(1,'published'),(2,'retracted'))
def cmp(a,b):if a < b:return-1if b < a:return1return0defEnum(*names):##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!classEnumClass(object):
__slots__ = names
def __iter__(self):return iter(constants)def __len__(self):return len(constants)def __getitem__(self, i):return constants[i]def __repr__(self):return'Enum'+ str(names)def __str__(self):return'enum '+ str(constants)classEnumValue(object):
__slots__ =('__value')def __init__(self, value): self.__value = value
Value= property(lambda self: self.__value)EnumType= property(lambda self:EnumType)def __hash__(self):return hash(self.__value)def __cmp__(self, other):# C fans might want to remove the following assertion# to make all enums comparable by ordinal value {;))assert self.EnumTypeis other.EnumType,"Only values from the same enum are comparable"return cmp(self.__value, other.__value)def __lt__(self, other):return self.__cmp__(other)<0def __eq__(self, other):return self.__cmp__(other)==0def __invert__(self):return constants[maximum - self.__value]def __nonzero__(self):return bool(self.__value)def __repr__(self):return str(names[self.__value])
maximum = len(names)-1
constants =[None]* len(names)for i, each in enumerate(names):
val =EnumValue(i)
setattr(EnumClass, each, val)
constants[i]= val
constants = tuple(constants)EnumType=EnumClass()returnEnumTypeif __name__ =='__main__':print('\n*** Enum Demo ***')print('--- Days of week ---')Days=Enum('Mo','Tu','We','Th','Fr','Sa','Su')print(Days)print(Days.Mo)print(Days.Fr)print(Days.Mo<Days.Fr)print( list(Days))for each inDays:print('Day:', each)print('--- Yes/No ---')Confirmation=Enum('No','Yes')
answer =Confirmation.Noprint('Your answer is not',~answer)
It gives you a class, and the class contains all the enums. The enums can be compared to each other, but don’t have any particular value; you can’t use them as an integer value. (I resisted this at first because I am used to C enums, which are integer values. But if you can’t use it as an integer, you can’t use it as an integer by mistake so overall I think it is a win.) Each enum is a unique value. You can print enums, you can iterate over them, you can test that an enum value is “in” the enum. It’s pretty complete and slick.
Edit (cfi): The above link is not Python 3 compatible. Here’s my port of enum.py to Python 3:
def cmp(a,b):
if a < b: return -1
if b < a: return 1
return 0
def Enum(*names):
##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!
class EnumClass(object):
__slots__ = names
def __iter__(self): return iter(constants)
def __len__(self): return len(constants)
def __getitem__(self, i): return constants[i]
def __repr__(self): return 'Enum' + str(names)
def __str__(self): return 'enum ' + str(constants)
class EnumValue(object):
__slots__ = ('__value')
def __init__(self, value): self.__value = value
Value = property(lambda self: self.__value)
EnumType = property(lambda self: EnumType)
def __hash__(self): return hash(self.__value)
def __cmp__(self, other):
# C fans might want to remove the following assertion
# to make all enums comparable by ordinal value {;))
assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
return cmp(self.__value, other.__value)
def __lt__(self, other): return self.__cmp__(other) < 0
def __eq__(self, other): return self.__cmp__(other) == 0
def __invert__(self): return constants[maximum - self.__value]
def __nonzero__(self): return bool(self.__value)
def __repr__(self): return str(names[self.__value])
maximum = len(names) - 1
constants = [None] * len(names)
for i, each in enumerate(names):
val = EnumValue(i)
setattr(EnumClass, each, val)
constants[i] = val
constants = tuple(constants)
EnumType = EnumClass()
return EnumType
if __name__ == '__main__':
print( '\n*** Enum Demo ***')
print( '--- Days of week ---')
Days = Enum('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')
print( Days)
print( Days.Mo)
print( Days.Fr)
print( Days.Mo < Days.Fr)
print( list(Days))
for each in Days:
print( 'Day:', each)
print( '--- Yes/No ---')
Confirmation = Enum('No', 'Yes')
answer = Confirmation.No
print( 'Your answer is not', ~answer)
>>>classEnum(int):...def __new__(cls, value):...if isinstance(value, str):...return getattr(cls, value)...elif isinstance(value, int):...return cls.__index[value]...def __str__(self):return self.__name
...def __repr__(self):return"%s.%s"%(type(self).__name__, self.__name)...class __metaclass__(type):...def __new__(mcls, name, bases, attrs):... attrs['__slots__']=['_Enum__name']... cls = type.__new__(mcls, name, bases, attrs)... cls._Enum__index= _index ={}...for base in reversed(bases):...if hasattr(base,'_Enum__index'):... _index.update(base._Enum__index)...# create all of the instances of the new class...for attr in attrs.keys():... value = attrs[attr]...if isinstance(value, int):... evalue = int.__new__(cls, value)... evalue._Enum__name= attr
... _index[value]= evalue
... setattr(cls, attr, evalue)...return cls
...
一个奇特的使用示例:
>>>classCitrus(Enum):...Lemon=1...Lime=2...>>>Citrus.LemonCitrus.Lemon>>>>>>Citrus(1)Citrus.Lemon>>>Citrus(5)Traceback(most recent call last):File"<stdin>", line 1,in<module>File"<stdin>", line 6,in __new__
KeyError:5>>>classFruit(Citrus):...Apple=3...Banana=4...>>>Fruit.AppleFruit.Apple>>>Fruit.LemonCitrus.Lemon>>>Fruit(1)Citrus.Lemon>>>Fruit(3)Fruit.Apple>>>"%d %s %r"%((Fruit.Apple,)*3)'3 Apple Fruit.Apple'>>>Fruit(1)isCitrus.LemonTrue
I have had occasion to need of an Enum class, for the purpose of decoding a binary file format. The features I happened to want is concise enum definition, the ability to freely create instances of the enum by either integer value or string, and a useful representation. Here’s what I ended up with:
>>> class Enum(int):
... def __new__(cls, value):
... if isinstance(value, str):
... return getattr(cls, value)
... elif isinstance(value, int):
... return cls.__index[value]
... def __str__(self): return self.__name
... def __repr__(self): return "%s.%s" % (type(self).__name__, self.__name)
... class __metaclass__(type):
... def __new__(mcls, name, bases, attrs):
... attrs['__slots__'] = ['_Enum__name']
... cls = type.__new__(mcls, name, bases, attrs)
... cls._Enum__index = _index = {}
... for base in reversed(bases):
... if hasattr(base, '_Enum__index'):
... _index.update(base._Enum__index)
... # create all of the instances of the new class
... for attr in attrs.keys():
... value = attrs[attr]
... if isinstance(value, int):
... evalue = int.__new__(cls, value)
... evalue._Enum__name = attr
... _index[value] = evalue
... setattr(cls, attr, evalue)
... return cls
...
A whimsical example of using it:
>>> class Citrus(Enum):
... Lemon = 1
... Lime = 2
...
>>> Citrus.Lemon
Citrus.Lemon
>>>
>>> Citrus(1)
Citrus.Lemon
>>> Citrus(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __new__
KeyError: 5
>>> class Fruit(Citrus):
... Apple = 3
... Banana = 4
...
>>> Fruit.Apple
Fruit.Apple
>>> Fruit.Lemon
Citrus.Lemon
>>> Fruit(1)
Citrus.Lemon
>>> Fruit(3)
Fruit.Apple
>>> "%d %s %r" % ((Fruit.Apple,)*3)
'3 Apple Fruit.Apple'
>>> Fruit(1) is Citrus.Lemon
True
Key features:
str(), int() and repr() all produce the most useful output possible, respectively the name of the enumartion, its integer value, and a Python expression that evaluates back to the enumeration.
Enumerated values returned by the constructor are limited strictly to the predefined values, no accidental enum values.
Enumerated values are singletons; they can be strictly compared with is
>>>from flufl.enum importEnum>>>classColors(Enum):... red =1... green =2... blue =3>>>for color inColors:print color
Colors.red
Colors.green
Colors.blue
>>> from flufl.enum import Enum
>>> class Colors(Enum):
... red = 1
... green = 2
... blue = 3
>>> for color in Colors: print color
Colors.red
Colors.green
Colors.blue
回答 21
def enum(*sequential,**named):
enums = dict(zip(sequential,[object()for _ in range(len(sequential))]),**named)return type('Enum',(), enums)
When using other implementations sited here (also when using named instances in my example) you must be sure you never try to compare objects from different enums. For here’s a possible pitfall:
>>>Numbers= enum_base(int, ONE=1, TWO=2, THREE=3)>>>Numbers.ONE
1>>> x =Numbers.TWO
>>>10+ x
12>>> type(Numbers)<type 'type'>>>> type(Numbers.ONE)<class'Enum'>>>> isinstance(x,Numbers)True
使用此方法可以完成的另一件有趣的事情是,通过覆盖内置方法来自定义特定行为:
def enum_repr(t,**enums):'''enums with a base class and repr() output'''classEnum(t):def __repr__(self):return'<enum {0} of type Enum({1})>'.format(self._name, t.__name__)for key,val in enums.items():
i =Enum(val)
i._name = key
setattr(Enum, key, i)returnEnum>>>Numbers= enum_repr(int, ONE=1, TWO=2, THREE=3)>>> repr(Numbers.ONE)'<enum ONE of type Enum(int)>'>>> str(Numbers.ONE)'1'
It’s elegant and clean looking, but it’s just a function that creates a class with the specified attributes.
With a little modification to the function, we can get it to act a little more ‘enumy’:
NOTE: I created the following examples by trying to reproduce the
behavior of pygtk’s new style ‘enums’ (like Gtk.MessageType.WARNING)
def enum_base(t, **enums):
'''enums with a base class'''
T = type('Enum', (t,), {})
for key,val in enums.items():
setattr(T, key, T(val))
return T
This creates an enum based off a specified type. In addition to giving attribute access like the previous function, it behaves as you would expect an Enum to with respect to types. It also inherits the base class.
Another interesting thing that can be done with this method is customize specific behavior by overriding built-in methods:
def enum_repr(t, **enums):
'''enums with a base class and repr() output'''
class Enum(t):
def __repr__(self):
return '<enum {0} of type Enum({1})>'.format(self._name, t.__name__)
for key,val in enums.items():
i = Enum(val)
i._name = key
setattr(Enum, key, i)
return Enum
>>> Numbers = enum_repr(int, ONE=1, TWO=2, THREE=3)
>>> repr(Numbers.ONE)
'<enum ONE of type Enum(int)>'
>>> str(Numbers.ONE)
'1'
The enum package from PyPI provides a robust implementation of enums. An earlier answer mentioned PEP 354; this was rejected but the proposal was implemented
http://pypi.python.org/pypi/enum.
Alexandru’s suggestion of using class constants for enums works quite well.
I also like to add a dictionary for each set of constants to lookup a human-readable string representation.
This serves two purposes: a) it provides a simple way to pretty-print your enum and b) the dictionary logically groups the constants so that you can test for membership.
def enum(*names):"""
SYNOPSIS
Well-behaved enumerated type, easier than creating custom classes
DESCRIPTION
Create a custom type that implements an enumeration. Similar in concept
to a C enum but with some additional capabilities and protections. See
http://code.activestate.com/recipes/413486-first-class-enums-in-python/.
PARAMETERS
names Ordered list of names. The order in which names are given
will be the sort order in the enum type. Duplicate names
are not allowed. Unicode names are mapped to ASCII.
RETURNS
Object of type enum, with the input names and the enumerated values.
EXAMPLES
>>> letters = enum('a','e','i','o','u','b','c','y','z')
>>> letters.a < letters.e
True
## index by property
>>> letters.a
a
## index by position
>>> letters[0]
a
## index by name, helpful for bridging string inputs to enum
>>> letters['a']
a
## sorting by order in the enum() create, not character value
>>> letters.u < letters.b
True
## normal slicing operations available
>>> letters[-1]
z
## error since there are not 100 items in enum
>>> letters[99]
Traceback (most recent call last):
...
IndexError: tuple index out of range
## error since name does not exist in enum
>>> letters['ggg']
Traceback (most recent call last):
...
ValueError: tuple.index(x): x not in tuple
## enums must be named using valid Python identifiers
>>> numbers = enum(1,2,3,4)
Traceback (most recent call last):
...
AssertionError: Enum values must be string or unicode
>>> a = enum('-a','-b')
Traceback (most recent call last):
...
TypeError: Error when calling the metaclass bases
__slots__ must be identifiers
## create another enum
>>> tags = enum('a','b','c')
>>> tags.a
a
>>> letters.a
a
## can't compare values from different enums
>>> letters.a == tags.a
Traceback (most recent call last):
...
AssertionError: Only values from the same enum are comparable
>>> letters.a < tags.a
Traceback (most recent call last):
...
AssertionError: Only values from the same enum are comparable
## can't update enum after create
>>> letters.a = 'x'
Traceback (most recent call last):
...
AttributeError: 'EnumClass' object attribute 'a' is read-only
## can't update enum after create
>>> del letters.u
Traceback (most recent call last):
...
AttributeError: 'EnumClass' object attribute 'u' is read-only
## can't have non-unique enum values
>>> x = enum('a','b','c','a')
Traceback (most recent call last):
...
AssertionError: Enums must not repeat values
## can't have zero enum values
>>> x = enum()
Traceback (most recent call last):
...
AssertionError: Empty enums are not supported
## can't have enum values that look like special function names
## since these could collide and lead to non-obvious errors
>>> x = enum('a','b','c','__cmp__')
Traceback (most recent call last):
...
AssertionError: Enum values beginning with __ are not supported
LIMITATIONS
Enum values of unicode type are not preserved, mapped to ASCII instead.
"""## must have at least one enum valueassert names,'Empty enums are not supported'## enum values must be stringsassert len([i for i in names ifnot isinstance(i, types.StringTypes)andnot \
isinstance(i, unicode)])==0,'Enum values must be string or unicode'## enum values must not collide with special function namesassert len([i for i in names if i.startswith("__")])==0,\
'Enum values beginning with __ are not supported'## each enum value must be unique from all othersassert names == uniquify(names),'Enums must not repeat values'classEnumClass(object):""" See parent function for explanation """
__slots__ = names
def __iter__(self):return iter(constants)def __len__(self):return len(constants)def __getitem__(self, i):## this makes xx['name'] possibleif isinstance(i, types.StringTypes):
i = names.index(i)## handles the more normal xx[0]return constants[i]def __repr__(self):return'enum'+ str(names)def __str__(self):return'enum '+ str(constants)def index(self, i):return names.index(i)classEnumValue(object):""" See parent function for explanation """
__slots__ =('__value')def __init__(self, value):
self.__value = value
value = property(lambda self: self.__value)
enumtype = property(lambda self: enumtype)def __hash__(self):return hash(self.__value)def __cmp__(self, other):assert self.enumtype is other.enumtype,'Only values from the same enum are comparable'return cmp(self.value, other.value)def __invert__(self):return constants[maximum - self.value]def __nonzero__(self):## return bool(self.value)## Original code led to bool(x[0])==False, not correctreturnTruedef __repr__(self):return str(names[self.value])
maximum = len(names)-1
constants =[None]* len(names)for i, each in enumerate(names):
val =EnumValue(i)
setattr(EnumClass, each, val)
constants[i]= val
constants = tuple(constants)
enumtype =EnumClass()return enumtype
Many doctests included here to illustrate what’s different about this approach.
def enum(*names):
"""
SYNOPSIS
Well-behaved enumerated type, easier than creating custom classes
DESCRIPTION
Create a custom type that implements an enumeration. Similar in concept
to a C enum but with some additional capabilities and protections. See
http://code.activestate.com/recipes/413486-first-class-enums-in-python/.
PARAMETERS
names Ordered list of names. The order in which names are given
will be the sort order in the enum type. Duplicate names
are not allowed. Unicode names are mapped to ASCII.
RETURNS
Object of type enum, with the input names and the enumerated values.
EXAMPLES
>>> letters = enum('a','e','i','o','u','b','c','y','z')
>>> letters.a < letters.e
True
## index by property
>>> letters.a
a
## index by position
>>> letters[0]
a
## index by name, helpful for bridging string inputs to enum
>>> letters['a']
a
## sorting by order in the enum() create, not character value
>>> letters.u < letters.b
True
## normal slicing operations available
>>> letters[-1]
z
## error since there are not 100 items in enum
>>> letters[99]
Traceback (most recent call last):
...
IndexError: tuple index out of range
## error since name does not exist in enum
>>> letters['ggg']
Traceback (most recent call last):
...
ValueError: tuple.index(x): x not in tuple
## enums must be named using valid Python identifiers
>>> numbers = enum(1,2,3,4)
Traceback (most recent call last):
...
AssertionError: Enum values must be string or unicode
>>> a = enum('-a','-b')
Traceback (most recent call last):
...
TypeError: Error when calling the metaclass bases
__slots__ must be identifiers
## create another enum
>>> tags = enum('a','b','c')
>>> tags.a
a
>>> letters.a
a
## can't compare values from different enums
>>> letters.a == tags.a
Traceback (most recent call last):
...
AssertionError: Only values from the same enum are comparable
>>> letters.a < tags.a
Traceback (most recent call last):
...
AssertionError: Only values from the same enum are comparable
## can't update enum after create
>>> letters.a = 'x'
Traceback (most recent call last):
...
AttributeError: 'EnumClass' object attribute 'a' is read-only
## can't update enum after create
>>> del letters.u
Traceback (most recent call last):
...
AttributeError: 'EnumClass' object attribute 'u' is read-only
## can't have non-unique enum values
>>> x = enum('a','b','c','a')
Traceback (most recent call last):
...
AssertionError: Enums must not repeat values
## can't have zero enum values
>>> x = enum()
Traceback (most recent call last):
...
AssertionError: Empty enums are not supported
## can't have enum values that look like special function names
## since these could collide and lead to non-obvious errors
>>> x = enum('a','b','c','__cmp__')
Traceback (most recent call last):
...
AssertionError: Enum values beginning with __ are not supported
LIMITATIONS
Enum values of unicode type are not preserved, mapped to ASCII instead.
"""
## must have at least one enum value
assert names, 'Empty enums are not supported'
## enum values must be strings
assert len([i for i in names if not isinstance(i, types.StringTypes) and not \
isinstance(i, unicode)]) == 0, 'Enum values must be string or unicode'
## enum values must not collide with special function names
assert len([i for i in names if i.startswith("__")]) == 0,\
'Enum values beginning with __ are not supported'
## each enum value must be unique from all others
assert names == uniquify(names), 'Enums must not repeat values'
class EnumClass(object):
""" See parent function for explanation """
__slots__ = names
def __iter__(self):
return iter(constants)
def __len__(self):
return len(constants)
def __getitem__(self, i):
## this makes xx['name'] possible
if isinstance(i, types.StringTypes):
i = names.index(i)
## handles the more normal xx[0]
return constants[i]
def __repr__(self):
return 'enum' + str(names)
def __str__(self):
return 'enum ' + str(constants)
def index(self, i):
return names.index(i)
class EnumValue(object):
""" See parent function for explanation """
__slots__ = ('__value')
def __init__(self, value):
self.__value = value
value = property(lambda self: self.__value)
enumtype = property(lambda self: enumtype)
def __hash__(self):
return hash(self.__value)
def __cmp__(self, other):
assert self.enumtype is other.enumtype, 'Only values from the same enum are comparable'
return cmp(self.value, other.value)
def __invert__(self):
return constants[maximum - self.value]
def __nonzero__(self):
## return bool(self.value)
## Original code led to bool(x[0])==False, not correct
return True
def __repr__(self):
return str(names[self.value])
maximum = len(names) - 1
constants = [None] * len(names)
for i, each in enumerate(names):
val = EnumValue(i)
setattr(EnumClass, each, val)
constants[i] = val
constants = tuple(constants)
enumtype = EnumClass()
return enumtype
While the original enum proposal, PEP 354, was rejected years ago, it keeps coming back up. Some kind of enum was intended to be added to 3.2, but it got pushed back to 3.3 and then forgotten. And now there’s a PEP 435 intended for inclusion in Python 3.4. The reference implementation of PEP 435 is flufl.enum.
As of April 2013, there seems to be a general consensus that something should be added to the standard library in 3.4—as long as people can agree on what that “something” should be. That’s the hard part. See the threads starting here and here, and a half dozen other threads in the early months of 2013.
Meanwhile, every time this comes up, a slew of new designs and implementations appear on PyPI, ActiveState, etc., so if you don’t like the FLUFL design, try a PyPI search.
回答 29
使用以下内容。
TYPE ={'EAN13': u'EAN-13','CODE39': u'Code 39','CODE128': u'Code 128','i25': u'Interleaved 2 of 5',}>>> TYPE.items()[('EAN13', u'EAN-13'),('i25', u'Interleaved 2 of 5'),('CODE39', u'Code 39'),('CODE128', u'Code 128')]>>> TYPE.keys()['EAN13','i25','CODE39','CODE128']>>> TYPE.values()[u'EAN-13', u'Interleaved 2 of 5', u'Code 39', u'Code 128']