Python Enum with exception: TypeError: Attempted to reuse ke



当枚举失败时,我试图重新定义它,但随后引发错误。

我的代码如下所示:

from enum import Enum
class FooEnum(Enum):
try:
foo = 3/0
except Exception as my_exception_instance:
print('An error occurred:', my_exception_instance)
foo=0

目标是3/0将引发异常,然后重新定义foo。然而,当我运行它,显示打印消息,但另一个错误是,这对我来说没有意义。下面是输出和堆栈跟踪:

An error occurred: division by zero
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-10-489d2391f28b> in <module>
1 from enum import Enum
2 
----> 3 class FooEnum(Enum):
4     try:
5         foo = 3/0
<ipython-input-10-489d2391f28b> in FooEnum()
6     except Exception as my_exception_instance:
7         print('An error occurred:', my_exception_instance)
----> 8         foo=0
/usr/lib/python3.6/enum.py in __setitem__(self, key, value)
90         elif key in self._member_names:
91             # descriptor overwriting an enum?
---> 92             raise TypeError('Attempted to reuse key: %r' % key)
93         elif not _is_descriptor(value):
94             if key in self:
TypeError: Attempted to reuse key: 'my_exception_instance'
消除此错误的唯一方法是在捕获异常时删除异常的使用:
from enum import Enum
class FooEnum(Enum):
try:
foo = 3/0
except:
print('An error occurred')
foo=0

则输出An error occurred

我正在使用python 3.6.9


编辑下面的代码更接近我的用例:

import tensorflow as tf
from enum import Enum
class VisualModels(Enum):

try:
MobileNet = tf.keras.applications.MobileNetV2
except Exception as e:
print(f'MobileNetV2 Not found, using MobileNet instead. Error: {e}.')
MobileNet = tf.keras.applications.MobileNet
# more models are defined similarly

发生这种情况的原因是:

  • _EnumDict跟踪所有使用的名称
  • _EnumDict认为my_exception_instance应该成为成员
  • Python在离开except子句时清除as变量
    • 通过将None赋值给my_exception_instance(然后删除变量)
    • 导致_EnumDict认为密钥正在被重用

一种解决方法(从Python 3.7开始)是将my_exception_instance添加到_ignore_1属性:

class FooEnum(Enum):
_ignore_ = 'my_exception_instance'
try:
foo = 3/0
except Exception as my_exception_instance:
print('An error occurred:', my_exception_instance)
foo=0

另一个解决方法是使my_exception_instance为全局:

class FooEnum(Enum):
global my_exception_instance
try:
foo = 3/0
except Exception as my_exception_instance:
print('An error occurred:', my_exception_instance)
foo=0

最后,如果不希望在枚举体中使用try/except:

class FallbackEnum(Enum):
def __new__(cls, *values):
# first actual value wins
member = object.__new__(cls)
fallback = False
for v in values:
try:
member._value_ = eval(v)
break
except Exception as e:
print('%s error: %s' % (v, e))
fallback = True
continue
else:
# never found a value
raise ValueError('no valid value found')
# if we get here, we found a value
if fallback:
# if the first value didn't work, print the one we did use
print('  using %s' % v)
return member

>>> class FooEnum(FallbackEnum):
...     foo = '3/0', '0'
... 
3/0 error: division by zero
using 0
>>> list(FooEnum)
[<FooEnum.foo: 0>]

1如果停留在Python 3.6,可以使用aenum

披露:我是Python标准库Enumenum34后端口和高级枚举(aenum)库的作者。

最新更新