【问题标题】:Doctest and Decorators in PythonPython 中的 Doctest 和装饰器
【发布时间】:2014-05-16 23:40:09
【问题描述】:

我试图使用 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)

效果很好

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

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

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

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

似乎什么都没有发生。

Desktop> python deco2.py 
Inside __init__()

这有什么问题?

【问题讨论】:

    标签: python decorator python-decorators doctest


    【解决方案1】:

    修饰函数(实际上是一个类实例)没有得到原始函数的__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
    

    【讨论】:

      【解决方案2】:

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

      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"
      

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

      您可以在这里使用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"
      

      【讨论】:

      • 不会functools.wraps 帮忙吗?
      • @metatoaster: functools.wraps()(和functools.update_wrapper())专门针对函数。实施后,它也可以在一个类上工作; wraps(f)(self) 会在那里做。
      猜你喜欢
      • 2020-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-16
      • 1970-01-01
      • 2010-10-16
      • 2014-02-13
      • 2011-03-01
      相关资源
      最近更新 更多