Python学习:带参数的装饰器

问题

前面写了一个统计函数执行时间的装饰器,默认使用print函数打印执行日志。日志打印,不能假设一定会用print,能否使用自定义的日志打印,比如logger

方案

先看前面提供的exec_time装饰器的代码:

 

import time
from functools import wraps

def exec_time():
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            beg = time.time() * 1000
            ret = func(*args, **kwargs)
            end = time.time() * 1000
            print('func:{%s} exec time is:{%.5f} ms' % (func.__name__, end - beg))
            return ret

        return wrapper

    return decorator

补充说明下,这里使用了语言内建的装饰器@wraps,@wraps的作用是来保留函数元数据。不然,函数信息会丢失。

我们默认使用print打印,调用者也可以指定其他log打印的方式。实现代码如下:

 

def exec_time(log=None):
    """
    功能描述:定义嵌套函数,用来打印出装饰的函数的执行时间
    :param func: func参数(自动)
    :param log: 日志打印函数类型
    :return: 返回内部wrapper函数
    """
    logger = log

    def decorate(func):

        @wraps(func)
        def wrapper(*args, **kwargs):
            """
            功能描述:定义开始时间和结束时间,将func夹在中间执行,取得其返回值
            :param args:
            :param kwargs:
            :return: 被装饰函数的实际返回值
            """
            start = time.time() * 1000
            func_ret = func(*args, **kwargs)
            end = time.time() * 1000
            if logger is None:
                print('func:{%s} exec time is:{%.5f} ms' % (func.__name__, end - start))
            else:
                logger.debug('func:{%s} exec time is:{%.5f} ms' % (func.__name__, end - start))
            return func_ret

        return wrapper

    # 返回嵌套的函数
    return decorate

测试代码:

 

import time
from common.exec_time import exec_time

class MyLogger:
    def debug(self, str):
        print('mylogger:debug:' + str)

class TestExecTime:
    def test_exec_time_01(self):
        @exec_time()
        def sleep_1s():
            time.sleep(1)

        sleep_1s()

    def test_exec_time_02(self):
        @exec_time(MyLogger())
        def sleep_2s():
            time.sleep(2)

        sleep_2s()

输出:

 

platform darwin -- Python 3.8.2, pytest-6.1.2, py-1.9.0, pluggy-0.13.1 -- /usr/local/bin/python3.8
cachedir: .pytest_cache
rootdir: /Users/xxx/data/code/github/learn-python/test
collecting ... collected 2 items

test_ExecTime.py::TestExecTime::test_exec_time_01 
test_ExecTime.py::TestExecTime::test_exec_time_02 

============================== 2 passed in 3.02s ===============================

Process finished with exit code 0
PASSED                 [ 50%]func:{sleep_1s} exec time is:{1000.36304} ms
PASSED                 [100%]mylogger:debug:func:{sleep_2s} exec time is:{2002.80005} ms

讨论

开发库的时候,库的接口设计假设/依赖越少越好,一方面是考虑通用性,另外一方面也会使得库具备较好的扩展性。因为一旦接口固定,后期修改成本就高得多了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
学习Python装饰器可以通过以下步骤进行: 1. 了解装饰器的概念和作用:装饰器是一种用于修改函数或类行为的函数,它可以在不修改原始函数代码的情况下添加额外的功能。装饰器可以用于日志记录、性能分析、权限校验等场景。 2. 学习装饰器的语法:装饰器是一个函数,它接受一个函数作为参数,并返回一个新的函数。装饰器通常使用`@`符号将其应用于目标函数。 3. 理解装饰器的执行顺序:装饰器是从上到下依次执行的,最后返回的函数将替换原始函数。 4. 掌握装饰器的常见应用场景:包括引入日志、函数执行时间统计、执行函数前预备处理、执行函数后清理功能、权限校验和缓存等。 5. 阅读相关的学习资料和示例代码:可以参考《深入浅出学习Python装饰器》和《Python装饰器学习总结》等文章,其中提供了详细的解释和示例代码,有助于更好地理解和掌握装饰器的使用。 以下是一个示例代码,演示了如何使用装饰器来统计函数的执行时间[^2]: ```python import time def timeit(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() execution_time = end_time - start_time print(f"函数 {func.__name__} 的执行时间为 {execution_time} 秒") return result return wrapper @timeit def my_function(): # 函数的具体实现 time.sleep(2) my_function() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值