【问题标题】:Is it possible to deprecate an Exception class?是否可以弃用异常类?
【发布时间】:2016-11-11 19:03:30
【问题描述】:

情况:我的库中有一些自定义异常类,供用户在其代码中使用。出于某种原因,我想重命名其中一个例外并弃用旧的。

将旧异常保留为别名并不难:

class MyNewError(ValueError):
    pass

MyOldError = MyNewError

但最终我想删除我的库的旧错误名称,因此我希望在下游代码中使用此自定义异常的用户收到 DeprecationWarning 通知,该错误将被删除。

但我想在以下用例中提出 DeprecationWarning(假设我的包含自定义异常的库称为 mypackage):

# downstream user code
import mypackage

...

try:
    ....
except mypackage.MyOldError:
    ....

所以我想在用户尝试捕获错误时发出警告,而不仅仅是在用户提出错误时发出警告。

有可能以某种方式做到这一点吗? (因为用户没有在这里调用我可以提出弃用警告的函数)

【问题讨论】:

  • 我不认为你可以 - 你大概不想每次有人导入 mypackage 时都发出警告,而且我认为没有一种明智的方法可以覆盖 __getitem__ at模块级别(参见例如stackoverflow.com/q/10438894/3001761 - 这很尴尬)。

标签: python exception


【解决方案1】:

您可以应用来自this answer 的hack/trick,将您的模块转换为一个类并拦截__getattr__() 操作:

mypackage/__init__.py

import sys
import warnings

class MyNewError(ValueError):
    pass

MyOldError = MyNewError

def foo():
    print('mypackage.foo(): raising MyNewError')
    raise MyNewError()

class Wrapper(object):
    def __init__(self, wrapped):
        self.wrapped = wrapped

    def __getattr__(self, name):
        if name == 'MyOldError':
            warnings.warn('MyOldError is deprecated, use MyNewError')

        return getattr(self.wrapped, name)

sys.modules[__name__] = Wrapper(sys.modules[__name__])

test.py

import mypackage

try:
    mypackage.foo()
except mypackage.MyOldError:
    print('Caught mypackage.MyOldError')

输出

$ python test.py 
mypackage.foo(): raising MyNewError
mypackage/__init__.py:18: UserWarning: MyOldError is deprecated, use MyNewError
  warnings.warn('MyOldError is deprecated, please use MyNewError')
Caught mypackage.MyOldError

【讨论】:

    【解决方案2】:

    当然可以在异常中引发异常,但如果用户没有预料到,它可能会导致问题。假设这只是您帖子中的一个失误,并且您没有要提出的 DeprecationWarning 异常,您可以执行以下操作:

    class MyOldError(MyNewError):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            deprecation_warning('Deprecated, please use MyNewError')
    
    >>> raise MyOldError
    Deprecated, please use MyNewError
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    __main__.MyOldError
    >>>
    

    【讨论】:

    • 谢谢!这适用于引发错误,但我也想显示弃用警告,以防有人试图 catch 错误(请参阅我的问题中的示例用例)
    • 啊,我明白你的意思了。使用metaclasses and magic methods 可以做到这一点,但我不确定这会有多大用处。与此同时,我会考虑一个优雅的解决方案,但没有承诺。也有人可能会打败我。
    猜你喜欢
    • 2019-05-06
    • 2013-11-11
    • 2017-09-04
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 2018-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多