我有一个枚举,其中一些成员已被弃用:
from enum import Enum
class Foo(Enum):
BAR = "bar"
BAZ = "baz" # deprecated
它如何获得以下行为:
Foo.BAR
,一切正常 Foo.BAZ
, DeprecationWarning
使用 warnings.warn("BAZ is deprecated", DeprecationWarning)
发布.之后一切正常。 Foo("baz")
和 Foo["BAZ"]
应该提出 DeprecationWarning
. 我尝试过但失败的事情:
_missing_
并且不要定义 BAZ
.不起作用,因为最后我仍然需要返回现有成员一段时间(直到我们的数据库清除了弃用的值)。但我不能动态地将成员添加到枚举中。如果我定义它,
_missing_
不叫。 __getattr__
, __getattribute__
.这些在访问成员的属性时被调用,例如Foo.BAZ.boo
, 不是在访问 Foo.BAZ
时.如果我可以覆盖 __getattr__
,我想这可以工作的 EnumMeta
然后制作 Enum
使用子元类。但是,我不知道如何做到这一点 __class_getitem__
: 保留用于静态类型,无论如何都不会调用。 _generate_next_value_
.此函数仅在创建类时调用,因此当类被调用一次时,无论是否调用了已弃用的成员,我都会收到弃用警告。但这不是我想要的。 TLDR:访问枚举成员时如何检测和调用函数?
我正在使用 python 3.8,所以新功能很好。
最佳答案
这似乎是 subclassing EnumMeta
的时代之一是正确的做法。
新元类将运行 _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
的作者, enum34
backport ,以及 Advanced Enumeration ( aenum
)图书馆。
关于python - 访问python枚举成员时如何检测和调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62299740/