Doctest and Decorators in Python

青春壹個敷衍的年華 提交于 2021-02-07 03:54:47

问题


I was trying to use Python decorator to catch exceptions and log the exceptions.

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)

It works fine

Desktop> python deco.py 
Inside __init__()
Inside __call__()
1 2 3
Sorry

The issue is that when I tried to use for testing with doctest

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

if __name__ == "__main__":
    import doctest
    doctest.testmod()

nothing seems to be happening.

Desktop> python deco2.py 
Inside __init__()

What's wrong with this?


回答1:


The decorated function (which is actually a class instance) doesn't get the __doc__ attribute of the original function (which is what doctest parses). You could just copy __doc__ over to the class instance, but ... Honestly, I don't really see the need for a class at all here -- you'd probably be better just using functools.wraps

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



回答2:


You need to copy the docstring over to your decorator:

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"

The decorator replaces the decorated function, and only by copying over the docstring would that attribute be visible to anyone.

You could make use of functools.update_wrapper() here to do the copying of the docstring, as well as several other attributes, for you:

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"


来源:https://stackoverflow.com/questions/22866510/doctest-and-decorators-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!