python - 将新类生成到命名空间的装饰器

标签 python decorator

我需要它的具体用例是弃用类名。

假设我们在早期版本中有类 A,我们想弃用它的名称但保持向后兼容性:

class A(B):
    def __init__(self, *args, **kwargs):
        warnings.warn('deprecation!')
        super(A, self).__init__(*args, **kwargs)

... B 现在有了正确的实现。

当我们创建一个类 A 时,我们会在这里遇到弃用警告。我们还可以在 __init__ 上使用装饰器的 deprecated 模块。

不过,我想跳过这个过程,少写一些代码,希望能达到这样的效果:

@deprecated_alias('A')
class B:
    # ... do something

我能否以某种方式将类名注入(inject)模块级命名空间,以便我可以像这样使用 A

最佳答案

Can I somehow inject the classname into the module-level namespace so that I can use A like this?

是的。类装饰器应该:

  • 使用 type 的 3 参数调用创建一个新类型,覆盖 __init__ 方法
  • 获取原始类的模块,sys.modules[original_class.__module__]
  • 使用 setattr 在模块命名空间中绑定(bind)新类
  • 返回原始类不变

例子:

import sys

def deprecated_alias(name):
    def decorator(class_):
        mod = sys.modules[class_.__module__]
        if hasattr(mod, name):
            raise Exception('uhoh, name collision')
        NewClass = type(name, (class_,), {'__init__': ...})
        setattr(mod, name, NewClass)
        return class_
    return decorator

@deprecated_alias('A')
class B:
    pass

我不推荐这种方法 - 魔法太多了。它会混淆 IDE 并破坏自动完成功能。

也许是一种不那么神奇的方法?这也可以做成一个装饰器,如果你需要控制更精细的继承细节,可以使用 __subclasscheck__/__subclasshook__

class A(B):
    def __init__(self, *args, **kwargs):
        warnings.warn('deprecation!')
        return B(*args, **kwargs)

关于python - 将新类生成到命名空间的装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51089327/

相关文章:

python - 带有 token 参数的 Django 电子邮件验证 URL

python - 可嵌套的超时装饰器? (即超时装饰函数调用超时装饰函数)

python - 使用装饰器从类外部动态添加方法

python装饰器和方法

python - 如何捕获像 mixin 这样的公共(public)类中的所有异常

c++ - 在 C++ 中使用函数装饰器(使用闭包)时出现意外的段错误

python - HDFStore 启动停止不起作用

Python 打印带元组和不带元组的字符串的不同行为

python - 具有现有进程的 wxPython GUI

python - urlfetch URL 的最大长度未记录?