Python decorator在命名空间中生成新类

Python decorator在命名空间中生成新类,python,decorator,Python,Decorator,我需要它的具体用例是不推荐类名 假设我们在早期版本中有一个类A,我们希望不推荐它的名称,但保持向后兼容性: class A(B): def __init__(self, *args, **kwargs): warnings.warn('deprecation!') super(A, self).__init__(*args, **kwargs) 。。。B现在有了正确的实现 当我们创建一个类a时,我们会在这里遇到一个弃用警告。我们还可以在\uuuu ini

我需要它的具体用例是不推荐类名

假设我们在早期版本中有一个类
A
,我们希望不推荐它的名称,但保持向后兼容性:

class A(B):
    def __init__(self, *args, **kwargs):
        warnings.warn('deprecation!')
        super(A, self).__init__(*args, **kwargs)
。。。B现在有了正确的实现

当我们创建一个类
a
时,我们会在这里遇到一个弃用警告。我们还可以在
\uuuu init\uuuu
上为装饰程序使用
不推荐的
模块

但是,我想跳过这个过程,编写更少的代码,并希望实现以下目标:

@deprecated_alias('A')
class B:
    # ... do something
我是否可以以某种方式将类名注入模块级名称空间,以便像这样使用
A

我是否可以以某种方式将类名注入到模块级名称空间中,以便使用这样的名称空间

对。类装饰器应该:

  • 使用
    type
    3参数调用,使用重写的
    \uuuu init\uuuu
    方法创建一个新类型
  • 获取原始类的模块,
    sys.modules[original\u class.\u\u module\u]
  • 使用
    setattr
  • 原封不动地返回原始类
例如:

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并中断自动完成

也许是一种不那么神奇的方法?如果需要控制更精细的继承细节,还可以将其制作成装饰器,并使用
\uuuu subasscheck\uuuu
/
\uuuu subasshook\uuuuu

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

虽然这并不完全是您所要求的,但它实际上没有那么神奇,并且最终的代码行数相同。它也更加明确:

import warnings

def deprecated(DeprecatedByClass):
    class Deprecated(DeprecatedByClass):
        def __new__(cls, *args, **kwargs):
            warnings.warn("deprecation!")
            return super(Deprecated, cls).__new__(cls, *args, **kwargs)

    return Deprecated
然后,您可以这样使用:

class B:
    pass

A = deprecated(B)

但是,你必须这样做吗?你可以在
\uuuu init\uuuuu
中执行
A=B
是否有不执行的理由:
@deprecates(A)
或相反:
@deprecated\u by(B)
没有理由。这只是一个特定于实现的细节,我对这两种方法都没有意见。尽管这里的
globals
可能是“错误的”
globals
,但我不确定装饰器是否必须比
def depreprecated\u alias(old\u name):def internal(cls):globals()[old\u name]复杂得多=cls return cls return INTERNAL
Dunno。不是我,我现在已经投票了,因为
globals
的问题已经解决了。元类可以解决这个问题,尽管我仍然不能100%确定OP到底需要什么。
functools.wrapps
在这里是不合适的。除此之外,回答得好。回答得好,但我认为你不应该在这里对两件不同的事情使用相同的名称(
cls
)。它不必要地混淆了问题。