如何警告类(名称)弃用 [英] How to warn about class (name) deprecation
问题描述
我已经将一个python类重命名为库的一部分。我愿意留下一个可能性,使用它的以前的名字一段时间,但是要提醒用户,它已过时,将在未来某个地方被删除。
为了提供向后兼容性,将足够使用如下的别名:
class NewClsName:
pass
OldClsName = NewClsName
我不知道如何标记 OldClsName
以优雅的方式弃用。也许我可以使 OldClsName
一个函数发出警告(对日志),并从其参数构造 NewClsName
使用 * args
和 ** kvargs
),但它似乎不够优雅
不幸的是,我不知道Python标准库废弃警告如何工作,但我想,可能有一些不错的魔法来处理废弃,例如根据一些解释器的命令行选项将其视为错误或静默。
问题是:如何警告用户关于使用过时的类别名)。
EDIT :函数方法不适用于我(我已经试过了),因为类有一些类方法(工厂方法),当 OldClsName
被定义为一个函数时,它不能被调用。以下代码不起作用:
class NewClsName(object):
@classmethod
def CreateVariant1 cls,...):
pass
@classmethod
def CreateVariant2(cls,...):
pass
def OldClsName(* args,** kwargs):
warnings.warn('OldClsName'类重命名为[...],
DeprecationWarning)
return NewClsName(* args,* * kwargs)
OldClsName.CreateVariant1(...)
:
AttributeError:'function'object没有属性'CreateVariant1'
pre>
继承是我唯一的选择吗?说实话,它对我看起来不是很干净 - 它通过引入不必要的派生来影响类层次结构。此外,
OldClsName不是NewClsName
在大多数情况下不是问题,但在使用库的编写不良的情况下可能会出现问题。
我也可以创建一个虚拟的,不相关的
OldClsName
类,并实现一个构造函数以及所有类方法的包装器,但是更糟解决方案。解决方案
也许我可以让OldClsName函数发出警告到
logs)并从它的参数(使用
* args和** kvargs)构造NewClsName对象,但它看起来不够优雅(或者可能是?)。
Yup,我认为这是很标准的做法:
def oldClsName(* args,** kwargs):
从warnings import warn
warn(get with the program!)
return NewClsName(* args,** kwargs)
唯一棘手的事情是,如果你有一些子类从
OldClsName
然后我们必须得到聪明。如果你只需要继续访问类方法,这应该这样做:类DeprecationHelper(object):
def __init __(self,new_target):
self.new_target = new_target
def _warn(self):
from warnings import warn
warn( !)
def __call __(self,* args,** kwargs):
self._warn()
return self.new_target(* args,** kwargs)
def __getattr __(self,attr):
self._warn()
return getattr(self.new_target,attr)
OldClsName = DeprecationHelper )
我没有测试过,但应该给你想法 -
__ call __
将处理正常实例化路由,__ getattr __
将捕获对类方法和仍然会产生警告,而不会影响你的类层次结构。I have renamed a python class being a part of a library. I am willing to leave a possibility to use its previous name for some time but would like to warn user that it's deprecated and will be removed somewhere in the future.
I think that to provide backward compatibility it will be enough to use an alias like that:
class NewClsName: pass OldClsName = NewClsName
I have no idea how to mark the
OldClsName
as deprecated in an elegant way. Maybe I could makeOldClsName
a function which emits a warning (to logs) and constructs theNewClsName
object from its parameters (using*args
and**kvargs
) but it doesn't seem elegant enough (or maybe it is?).Unfortunately, I don't know how Python standard library deprecation warnings work but I imagine that there may be some nice magic to deal with deprecation, e.g. allowing treating it as errors or silencing depending on some interpreter's command line option.
The question is: How to warn users about using an obsolete class alias (or obsolete class in general).
EDIT: The function approach doesn't work for me (I already gave it a try) because the class has some class methods (factory methods) which can't be called when the
OldClsName
is defined as a function. Following code won't work:class NewClsName(object): @classmethod def CreateVariant1( cls, ... ): pass @classmethod def CreateVariant2( cls, ... ): pass def OldClsName(*args, **kwargs): warnings.warn("The 'OldClsName' class was renamed [...]", DeprecationWarning ) return NewClsName(*args, **kwargs) OldClsName.CreateVariant1( ... )
Because of:
AttributeError: 'function' object has no attribute 'CreateVariant1'
Is inheritance my only option? To be honest, it doesn't look very clean to me - it affects class hierarchy through introduction of unnecessary derivation. Additionally,
OldClsName is not NewClsName
what is not an issue in most cases but may be a problem in case of poorly written code using the library.I could also create a dummy, unrelated
OldClsName
class and implement a constructor as well as wrappers for all class methods in it, but it is even worse solution, in my opinion.解决方案Maybe I could make OldClsName a function which emits a warning (to logs) and constructs the NewClsName object from its parameters (using *args and **kvargs) but it doesn't seem elegant enough (or maybe it is?).
Yup, I think that's pretty standard practice:
def OldClsName(*args, **kwargs): from warnings import warn warn("get with the program!") return NewClsName(*args, **kwargs)
The only tricky thing is if you have things that subclass from
OldClsName
- then we have to get clever. If you just need to keep access to class methods, this should do it:class DeprecationHelper(object): def __init__(self, new_target): self.new_target = new_target def _warn(self): from warnings import warn warn("Get with the program!") def __call__(self, *args, **kwargs): self._warn() return self.new_target(*args, **kwargs) def __getattr__(self, attr): self._warn() return getattr(self.new_target, attr) OldClsName = DeprecationHelper(NewClsName)
I haven't tested it, but that should give you the idea -
__call__
will handle the normal-instantation route,__getattr__
will capture accesses to the class methods & still generate the warning, without messing with your class heirarchy.这篇关于如何警告类(名称)弃用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!