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
)。它不必要地混淆了问题。