Python中的Doctest和Decorators

pro*_*eek 4 python doctest decorator python-decorators

我试图使用Python装饰器来捕获异常并记录异常.

import os.path
import shutil

class log(object):
    def __init__(self, f):
        print "Inside __init__()"
        self.f = f

    def __call__(self, *args):
        print "Inside __call__()"
        try:
            self.f(*args)
        except Exception:
            print "Sorry"

@log
def testit(a, b, c):
    print a,b,c
    raise RuntimeError()

if __name__ == "__main__":
    testit(1,2,3)
Run Code Online (Sandbox Code Playgroud)

它工作正常

Desktop> python deco.py 
Inside __init__()
Inside __call__()
1 2 3
Sorry
Run Code Online (Sandbox Code Playgroud)

问题是,当我尝试使用doctest进行测试时

@log
def testit(a, b, c):
    """
    >>> testit(1,2,3)
    """
    print a,b,c
    raise RuntimeError()

if __name__ == "__main__":
    import doctest
    doctest.testmod()
Run Code Online (Sandbox Code Playgroud)

似乎没有任何事情发生.

Desktop> python deco2.py 
Inside __init__()
Run Code Online (Sandbox Code Playgroud)

这有什么问题?

mgi*_*son 8

修饰函数(实际上是一个类实例)不会获得__doc__原始函数的属性(这就是doctest解析).你可以复制__doc__到类实例,但是......老实说,我真的没有看到这里需要一个类 - 你可能更好只是使用functools.wraps

import functools
def log(func):
    @functools.wraps(func)
    def wrapper(*args):
        try:
            return func(*args)
        except Exception:
            print "sorry"
    return wrapper
Run Code Online (Sandbox Code Playgroud)


Mar*_*ers 6

您需要将文档字符串复制到装饰器中:

class log(object):
    def __init__(self, f):
        print "Inside __init__()"
        self.f = f
        self.__doc__ = f.__doc__

    def __call__(self, *args):
        print "Inside __call__()"
        try:
            self.f(*args)
        except Exception:
            print "Sorry"
Run Code Online (Sandbox Code Playgroud)

装饰器替换了装饰函数,并且只有通过复制文档字符串,该属性才对任何人可见。

您可以利用functools.update_wrapper()此处为您复制文档字符串以及其他几个属性:

from functools import update_wrapper

class log(object):
    def __init__(self, f):
        print "Inside __init__()"
        self.f = f
        update_wrapper(self, f)

    def __call__(self, *args):
        print "Inside __call__()"
        try:
            self.f(*args)
        except Exception:
            print "Sorry"
Run Code Online (Sandbox Code Playgroud)