我需要的特定用例是弃用类名。
假设我们在较早的版本中有类A
,并且我们想弃用其名称,但保持向后兼容性:
class A(B):
def __init__(self, *args, **kwargs):
warnings.warn('deprecation!')
super(A, self).__init__(*args, **kwargs)
...并且B现在具有正确的实现。
当我们创建类A
时,我们将在此处遇到弃用警告。我们还可以将deprecated
模块用于__init__
上的装饰器。
但是,我想跳过此过程并编写更少的代码,并希望实现以下目标:
@deprecated_alias('A')
class B:
# ... do something
我可以以某种方式将类名注入模块级名称空间中,以便可以像这样使用A
吗?
答案 0 :(得分:4)
我可以以某种方式将类名注入模块级名称空间中,以便可以像这样使用A吗?
是的。类装饰器应:
__init__
的三参数调用,使用覆盖的type
方法创建新类型sys.modules[original_class.__module__]
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并破坏自动完成。
也许不是那么神奇的方法?也可以将其制成装饰器,如果需要控制继承的详细信息,请使用__subclasscheck__
/ __subclasshook__
。
class A(B):
def __init__(self, *args, **kwargs):
warnings.warn('deprecation!')
return B(*args, **kwargs)
答案 1 :(得分:2)
虽然这并不是您所要求的,但它的魔力却少得多,并且最终代码行数相同。它也更加明确:
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)