Run*_*ith 6 python enums deprecation-warning
我有一个枚举,其中一些成员已被弃用:
from enum import Enum
class Foo(Enum):
BAR = "bar"
BAZ = "baz" # deprecated
Run Code Online (Sandbox Code Playgroud)
它如何获得以下行为:
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,所以新功能很好。
这似乎是子类化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
Run Code Online (Sandbox Code Playgroud)
新基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,
)
Run Code Online (Sandbox Code Playgroud)
以及我们Enum弃用成员的示例:
class Foo(DeprecatedEnum):
BAR = "bar"
BAZ = "baz", "use something else"
Run Code Online (Sandbox Code Playgroud)
和警告(来自测试脚本):
# 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']
Run Code Online (Sandbox Code Playgroud)
以及所有已弃用的成员Foo:
>>> print([m.name for m in Foo if m._args])
['BAZ']
Run Code Online (Sandbox Code Playgroud)
披露:我是Python stdlibEnum、enum34backport和Advanced Enumeration ( aenum) 库的作者。
| 归档时间: |
|
| 查看次数: |
384 次 |
| 最近记录: |