如何警告类(名称)弃用 [英] How to warn about class (name) deprecation

查看:167
本文介绍了如何警告类(名称)弃用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经将一个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 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?).

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆