gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 11:48:44 30 4
gpt4 key购买 nike

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

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_ .此函数仅在创建类时调用,因此当类被调用一次时,无论是否调用了已弃用的成员,我都会收到弃用警告。但这不是我想要的。
  • this question .它不能解决我的问题,因为目标是在迭代过程中过滤已弃用的成员。

  • 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/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com