我需要它的具体用例是弃用类名。
假设我们在早期版本中有类 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/