Python装饰器神器@wraps(func)

遇到问题:

因为本人之前是用的unittest框架写的自动化脚本,已经预先写好了log日志模块的装饰器。后需将unittest替换成pytest,用到了pytest中功能强大的fixture,但是读取coftest.py中的fixture后,pytest的测试用例中填写fixture的方法名,执行,却发现自己写log装饰器报missing 1 required positional argument

  • 同时使用fixture和装饰器代码:


    image.png
  • 报错:


    image.png

解决问题途径:

发现同样的情况下,加上@allure.step("")装饰器却不会报该错,查看allure的源码

解决问题:

allure源码中,发现装饰器中加了一个@wraps(func),解决上述问题

以下介绍wraps相关:

Python中被装饰后的函数,函数名等函数属性会发生改变(相当于另一个函数了),所以,Python的functools包中提供了一个叫wraps的装饰器来解决该问题。它能使其保留原有函数的结构。

  • 不加@wraps()的装饰器:
import time


class MyLog(object):

    def __call__(self, func):
        def my_log(*args, **kwargs):
            """这里是my_log的docstring"""
            start = time.time()
            res = func(*args, **kwargs)
            end = time.time()
            print('|运行时长:{:.4f}'.format(end - start))
            return res
        return my_log


@MyLog()
def is_test():
    """这里是is_test的docstring"""
    print("一个测试方法")


print("__name__: ", is_test.__name__)
print("__doc__:  ", is_test.__doc__)

运行结果:


image.png

看运行结果,会发现,被装饰器装饰后的函数,name和docstring都发生了变化

  • 加了@wraps()的装饰器:
import time
from functools import wraps


class MyLog(object):

    def __call__(self, func):
        @wraps(func)
        def my_log(*args, **kwargs):
            """这里是my_log的docstring"""
            start = time.time()
            res = func(*args, **kwargs)
            end = time.time()
            print('|运行时长:{:.4f}'.format(end - start))
            return res
        return my_log


@MyLog()
def is_test():
    """这里是is_test的docstring"""
    print("一个测试方法")


print("__name__: ", is_test.__name__)
print("__doc__:  ", is_test.__doc__)

运行结果:


image.png

看运行结果,会发现,装饰器加了@wraps后,被装饰器装饰后的函数,还是保持原有的状态

  • 装饰器的作用: 在不改变原有功能代码的基础上,添加额外的功能。
  • @wraps(func)的作用: 不改变使用装饰器原有函数的结构(如name, doc)

你可能感兴趣的:(Python装饰器神器@wraps(func))