如何在访问 python 枚举成员时检测和调用函数

How do I detect and invoke a function when a python enum member is accessed

我有一个枚举,其中一些成员已被弃用:

from enum import Enum

class Foo(Enum):
    BAR = "bar"
    BAZ = "baz"  # deprecated

它如何获得以下行为:

我尝试过但失败的事情:

TLDR:访问枚举成员时如何检测和调用函数?

我正在使用 python 3.8,所以新功能很好。

这似乎是 应该做的事情之一。

新的元类将 运行 一个 _on_access 方法,如果它存在,每当访问一个成员时:

class OnAccess(EnumMeta):
    """
    runs a user-specified function whenever member is accessed
    """
    #
    def __getattribute__(cls, name):
        obj = super().__getattribute__(name)
        if isinstance(obj, Enum) and obj._on_access:
            obj._on_access()
        return obj
    #
    def __getitem__(cls, name):
        member = super().__getitem__(name)
        if member._on_access:
            member._on_access()
        return member
    #
    def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1):
        obj = super().__call__(value, names, module=module, qualname=qualname, type=type, start=start)
        if isinstance(obj, Enum) and obj._on_access:
            obj._on_access()
        return obj

新基础 Enum 将创建成员时的任何额外参数视为 deprecate 函数的参数,并且仅在提供额外参数时才将 _on_access 属性设置为该函数:

class DeprecatedEnum(Enum, metaclass=OnAccess):
    #
    def __new__(cls, value, *args):
        member = object.__new__(cls)
        member._value_ = value
        member._args = args
        member._on_access = member.deprecate if args else None
        return member
    #
    def deprecate(self):
        args = (self.name, ) + self._args
        import warnings
        warnings.warn(
                "member %r is deprecated; %s" % args,
                DeprecationWarning,
                stacklevel=3,
                )

我们的示例 Enum 包含已弃用的成员:

class Foo(DeprecatedEnum):
    BAR = "bar"
    BAZ = "baz", "use something else"

和警告(来自测试脚本):

# no warning here
list(Foo)

# nor for non-deprecated members
Foo.BAR

# but direct use of deprecated members does generate warnings
Foo.BAZ
/home/ethan/test:74: DeprecationWarning: member 'BAZ' is deprecated; use something else
  Foo.BAZ

Foo('baz')
/home/ethan/test:75: DeprecationWarning: member 'BAZ' is deprecated; use something else
  Foo('baz')

Foo['BAZ']
/home/ethan/test:76: DeprecationWarning: member 'BAZ' is deprecated; use something else
  Foo['BAZ']

以及 Foo 中所有已弃用的成员:

>>> print([m.name for m in Foo if m._args])
['BAZ']

披露:我是 Python stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) 库的作者。