python标准库中的装饰器(特别是@deprecated)

我需要将例程标记为已弃用,但显然不存在用于弃用的标准库装饰器。 我知道它的食谱和警告模块,但我的问题是:为什么没有这个(普通)任务的标准库装饰器?

附加问题:标准库中是否有标准的装饰器?

这里有一些摘录,从莱昂德罗引用的那些修改:

import warnings import functools def deprecated(func): """This is a decorator which can be used to mark functions as deprecated. It will result in a warning being emmitted when the function is used.""" @functools.wraps(func) def new_func(*args, **kwargs): warnings.simplefilter('always', DeprecationWarning) #turn off filter warnings.warn("Call to deprecated function {}.".format(func.__name__), category=DeprecationWarning, stacklevel=2) warnings.simplefilter('default', DeprecationWarning) #reset filter return func(*args, **kwargs) return new_func # Examples @deprecated def some_old_function(x,y): return x + y class SomeClass: @deprecated def some_old_method(self, x,y): return x + y 

因为在某些解释器中暴露的第一个解决scheme(没有filter处理)可能导致警告抑制。

这是另一个解决scheme:

这个装饰器(实际上是一个装饰器工厂 )允许你给出一个理由信息。 通过提供源文件名行号来帮助开发人员诊断问题也更加有用。

编辑 :此代码使用零的build议:它通过warnings.warn(msg, category=DeprecationWarning, stacklevel=2)replacewarnings.warn_explicit行,它打印函数调用站点,而不是函数定义站点。 它使debugging更容易。

EDIT2 :这个版本允许开发者指定一个可选的“原因”消息。

 import functools import inspect import warnings string_types = (type(b''), type(u'')) def deprecated(reason): """ This is a decorator which can be used to mark functions as deprecated. It will result in a warning being emitted when the function is used. """ if isinstance(reason, string_types): # The @deprecated is used with a 'reason'. # # .. code-block:: python # # @deprecated("please, use another function") # def old_function(x, y): # pass def decorator(func1): if inspect.isclass(func1): fmt1 = "Call to deprecated class {name} ({reason})." else: fmt1 = "Call to deprecated function {name} ({reason})." @functools.wraps(func1) def new_func1(*args, **kwargs): warnings.simplefilter('always', DeprecationWarning) warnings.warn( fmt1.format(name=func1.__name__, reason=reason), category=DeprecationWarning, stacklevel=2 ) warnings.simplefilter('default', DeprecationWarning) return func1(*args, **kwargs) return new_func1 return decorator elif inspect.isclass(reason) or inspect.isfunction(reason): # The @deprecated is used without any 'reason'. # # .. code-block:: python # # @deprecated # def old_function(x, y): # pass func2 = reason if inspect.isclass(func2): fmt2 = "Call to deprecated class {name}." else: fmt2 = "Call to deprecated function {name}." @functools.wraps(func2) def new_func2(*args, **kwargs): warnings.simplefilter('always', DeprecationWarning) warnings.warn( fmt2.format(name=func2.__name__), category=DeprecationWarning, stacklevel=2 ) warnings.simplefilter('default', DeprecationWarning) return func2(*args, **kwargs) return new_func2 else: raise TypeError(repr(type(reason))) 

你可以使用这个装饰器来实现函数方法

这是一个简单的例子:

 @deprecated("use another function") def some_old_function(x, y): return x + y class SomeClass(object): @deprecated("use another method") def some_old_method(self, x, y): return x + y @deprecated("use another class") class SomeOldClass(object): pass some_old_function(5, 3) SomeClass().some_old_method(8, 9) SomeOldClass() 

你会得到:

 deprecated_example.py:59: DeprecationWarning: Call to deprecated function or method some_old_function (use another function). some_old_function(5, 3) deprecated_example.py:60: DeprecationWarning: Call to deprecated function or method some_old_method (use another method). SomeClass().some_old_method(8, 9) deprecated_example.py:61: DeprecationWarning: Call to deprecated class SomeOldClass (use another class). SomeOldClass() 

EDIT3:这个装饰器现在是Deprecated库的一部分:

  • Python包索引(PyPi)
  • GitHub网站
  • 阅读文档
  • 电子书在Lulu.com上

classmethod()staticmethod()和各种property装饰器是重要的。 在contextlib还有一个,还有其他一些较less使用的。

我想原因是Python代码不能静态处理(就像它为C ++编译器所做的那样),在实际使用它之前,你不能警告使用一些东西。 我不认为这是一个好主意,垃圾邮件的用户与一堆消息“警告:此脚本的开发人员正在使用不推荐使用的API”。

更新:但是你可以创build一个将原始函数转换成另一个的装饰器。 新function将标记/检查开关,告诉这个function已被调用,只有在开关打开状态才会显示信息。 和/或在退出时,它可以打印程序中使用的所有弃用function的列表。

更新:我认为更好,当我们显示DeprecationWarning只有第一次为每个代码行 ,当我们可以发送一些消息:

 import inspect import traceback import warnings import functools import time def deprecated(message: str = ''): """ This is a decorator which can be used to mark functions as deprecated. It will result in a warning being emitted when the function is used first time and filter is set for show DeprecationWarning. """ def decorator_wrapper(func): @functools.wraps(func) def function_wrapper(*args, **kwargs): current_call_source = '|'.join(traceback.format_stack(inspect.currentframe())) if current_call_source not in function_wrapper.last_call_source: warnings.warn("Function {} is now deprecated! {}".format(func.__name__, message), category=DeprecationWarning, stacklevel=2) function_wrapper.last_call_source.add(current_call_source) return func(*args, **kwargs) function_wrapper.last_call_source = set() return function_wrapper return decorator_wrapper @deprecated('You must use my_func2!') def my_func(): time.sleep(.1) print('aaa') time.sleep(.1) def my_func2(): print('bbb') warnings.simplefilter('always', DeprecationWarning) # turn off filter print('before cycle') for i in range(5): my_func() print('after cycle') my_func() my_func() my_func() 

结果:

 before cycle C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:45: DeprecationWarning: Function my_func is now deprecated! You must use my_func2! aaa aaa aaa aaa aaa after cycle C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:47: DeprecationWarning: Function my_func is now deprecated! You must use my_func2! aaa C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:48: DeprecationWarning: Function my_func is now deprecated! You must use my_func2! aaa C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:49: DeprecationWarning: Function my_func is now deprecated! You must use my_func2! aaa Process finished with exit code 0 

我们可以点击警告path,然后进入PyCharm中的行。