获取有关在Python装饰器中调用代码的具体信息

时间:2011-02-15 01:30:54

标签: python decorator

我有一个Python装饰器,我用它来标记函数/方法已弃用。它足够,但我希望它能够更好地。具体来说,我想要它做的是能够告诉完全行号已弃用的函数。这样就不必通过源代码来查找它了;相反,警告会将它们直接指向它。 (这并不是说有人不会通过代码来查找其他使用调用已弃用函数的地方,但他们不应该这样做以响应这样的警告,恕我直言。)

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

1 个答案:

答案 0 :(得分:9)

你不需要那些东西:

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

秘密是stacklevel的{​​{1}}参数。 docs说:

  

stacklevel参数可以由用Python编写的包装函数使用,(...)使警告引用deprecation()的调用者,而不是引用deprecation()本身(因为后者)会破坏警告信息的目的。)