Python Enum with exception: TypeError: Attempted to reuse key:

Python Enum with exception: TypeError: Attempted to reuse key:

我试图在失败时重新定义枚举,但随后出现错误。

我的代码如下所示:

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 stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) 库的作者。