Skip to main content
 首页 » 编程设计

python之获取有关在 Python 装饰器中调用代码的特定信息

2025年05月04日10飞鱼

我有一个 Python 装饰器,用于将函数/方法标记为已弃用。它的工作足够,但我希望它更好。具体来说,我想让它做的是能够将调用的确切行号告诉已弃用的函数。这样一来,就不必通过 grep 查找源代码了;相反,警告将直接指向它。 (这并不是说有人无论如何都不会 grep 遍历代码来寻找其他调用已弃用函数的地方,但恕我直言,他们不应该为了响应这样的警告而这样做)。

class deprecated(object): 
    '''This class implements the deprecated decorator. 
 
    This decorator is used to mark a function or a class as 
    deprecated.  A message indicating why it is deprecated (and what 
    to use instead) must be provided.  Also, a version number 
    indicating when the function or class was deprecated must _also_ 
    be provided. 
 
    Optionally, a third parameter may be passed that indicates when 
    the deprecated functionality will actually be removed.''' 
    def __init__(self, message, version, to_be_removed_in_version = None): 
        self._message = message 
        self._version = version 
        self._removal_version = to_be_removed_in_version 
        return 
 
    def __call__(self, func): 
        def wrapper(*args, **kwargs): 
            import warnings 
            import inspect 
 
            frame = inspect.currentframe().f_back 
            where = 'Called from {0} somewhere after line {1}.' 
            where = where.format(frame.f_code.co_filename, 
                                 frame.f_code.co_firstlineno) 
            msg = 'Call to deprecated function {0} (since {1}{2}) {3}' 
 
            if self._removal_version is not None: 
                removal = ', scheduled for removal by version {0}' 
                removal = removal.format(self._removal_version) 
 
            msg = msg.format(func.__name__, self._version, 
                             removal, where) 
            warnings.warn_explicit(msg, category = DeprecationWarning, 
                                   filename = func.func_code.co_filename, 
                                   lineno = func.func_code.co_firstlineno + 1) 
 
            return func(*args, **kwargs) 
 
        wrapper.__name__ = func.__name__ 
        wrapper.__doc__ = func.__doc__ 
        wrapper.__dict__.update(func.__dict__) 
        return wrapper 

请您参考如下方法:

你不需要那么多东西:

from functools import wraps 
import warnings 
 
def deprecated(message, newfunc): 
    def _deprecated(func): 
        @wraps(func) 
        def _wrapped(*args, **kwds): 
            warnings.warn(message + ', ' + newfunc,  
                DeprecationWarning, stacklevel=2) 
            return func(*args, **kwds) 
        return _wrapped 
    return _deprecated 

就是这样!检查一下:

@deprecated("function foo is deprecated", "use bar instead") 
def foo(bar): 
    print 'Hello', bar 
foo('World') 

我明白了

teste.py:17: DeprecationWarning: function foo is deprecated, use bar instead 
  foo('World') 
Hello World 

另一个例子:

class Foo(object): 
    @deprecated("method bar is deprecated", "use baz instead") 
    def bar(self, baz): 
        print 'Goodbye', baz 
f = Foo() 
f.bar('World') 

我得到:

teste.py:25: DeprecationWarning: method bar is deprecated, use baz instead 
  f.bar('World') 
Goodbye World 

secret 是 warnings.warn 的 stacklevel 参数。 docs说:

The stacklevel argument can be used by wrapper functions written in Python, (...) makes the warning refer to deprecation()‘s caller, rather than to the source of deprecation() itself (since the latter would defeat the purpose of the warning message).