流畅的python系列:装饰器

文章展示了一个名为`clock`的Python装饰器,用于测量函数执行的时间。装饰器内部定义了`clocked`函数,记录开始时间,调用原函数,计算执行时间并打印。示例中,`clock`装饰器应用到了`snooze`和`factorial`函数上,显示了它们的执行时间和结果。`factorial`函数通过递归计算阶乘。
摘要由CSDN通过智能技术生成

1-1

from dis import dis
import time

def clock(func):
    def clocked(*args):
        t0 = time.perf_counter()
        result = func(*args)
        elasped = time.perf_counter() - t0
        name = func.__name__
        arg_str = ','.join(repr(arg) for arg in args)
        print('[%0.8fs] %s(%s) -> %r' %(elasped,name,arg_str,result))
        return result
    return clocked

@clock
def snooze(seconds):
    time.sleep(seconds)

@clock
def factorial(n):
    if n < 2:
        return 1
    else:
        return n *factorial(n-1)

if __name__=='__main__':
    dis(clock)
    print('*' * 40,'calling snooze(.123)')
    snooze(.123)
    print('*' * 40,'calling factorial(6)')
    print('6!=',factorial(6))

输出

D:\python3.9.7\python.exe D:/my-python-test/liuchangdepython/decorate.py
  5           0 LOAD_CLOSURE             0 (func)
              2 BUILD_TUPLE              1
              4 LOAD_CONST               1 (<code object clocked at 0x0000025028D6B240, file "D:\my-python-test\liuchangdepython\decorate.py", line 5>)
              6 LOAD_CONST               2 ('clock.<locals>.clocked')
              8 MAKE_FUNCTION            8 (closure)
             10 STORE_FAST               1 (clocked)

 13          12 LOAD_FAST                1 (clocked)
             14 RETURN_VALUE

Disassembly of <code object clocked at 0x0000025028D6B240, file "D:\my-python-test\liuchangdepython\decorate.py", line 5>:
  6           0 LOAD_GLOBAL              0 (time)
              2 LOAD_METHOD              1 (perf_counter)
              4 CALL_METHOD              0
              6 STORE_FAST               1 (t0)

  7           8 LOAD_DEREF               0 (func)
             10 LOAD_FAST                0 (args)
             12 CALL_FUNCTION_EX         0
             14 STORE_FAST               2 (result)

  8          16 LOAD_GLOBAL              0 (time)
             18 LOAD_METHOD              1 (perf_counter)
             20 CALL_METHOD              0
             22 LOAD_FAST                1 (t0)
             24 BINARY_SUBTRACT
             26 STORE_FAST               3 (elasped)

  9          28 LOAD_DEREF               0 (func)
             30 LOAD_ATTR                2 (__name__)
             32 STORE_FAST               4 (name)

 10          34 LOAD_CONST               1 (',')
             36 LOAD_METHOD              3 (join)
             38 LOAD_CONST               2 (<code object <genexpr> at 0x0000025028D6B190, file "D:\my-python-test\liuchangdepython\decorate.py", line 10>)
             40 LOAD_CONST               3 ('clock.<locals>.clocked.<locals>.<genexpr>')
             42 MAKE_FUNCTION            0
             44 LOAD_FAST                0 (args)
             46 GET_ITER
             48 CALL_FUNCTION            1
             50 CALL_METHOD              1
             52 STORE_FAST               5 (arg_str)

 11          54 LOAD_GLOBAL              4 (print)
             56 LOAD_CONST               4 ('[%0.8fs] %s(%s) -> %r')
             58 LOAD_FAST                3 (elasped)
             60 LOAD_FAST                4 (name)
             62 LOAD_FAST                5 (arg_str)
             64 LOAD_FAST                2 (result)
             66 BUILD_TUPLE              4
             68 BINARY_MODULO
             70 CALL_FUNCTION            1
             72 POP_TOP

 12          74 LOAD_FAST                2 (result)
             76 RETURN_VALUE

Disassembly of <code object <genexpr> at 0x0000025028D6B190, file "D:\my-python-test\liuchangdepython\decorate.py", line 10>:
 10           0 LOAD_FAST                0 (.0)
        >>    2 FOR_ITER                14 (to 18)
              4 STORE_FAST               1 (arg)
              6 LOAD_GLOBAL              0 (repr)
              8 LOAD_FAST                1 (arg)
             10 CALL_FUNCTION            1
             12 YIELD_VALUE
             14 POP_TOP
             16 JUMP_ABSOLUTE            2
        >>   18 LOAD_CONST               0 (None)
             20 RETURN_VALUE
**************************************** calling snooze(.123)
[0.12288130s] snooze(0.123) -> None
**************************************** calling factorial(6)
[0.00000080s] factorial(1) -> 1
[0.00001210s] factorial(2) -> 2
[0.00001910s] factorial(3) -> 6
[0.00002510s] factorial(4) -> 24
[0.00003130s] factorial(5) -> 120
[0.00003950s] factorial(6) -> 720
6!= 720

Process finished with exit code 0

代码解释

❶ 定义内部函数 clocked, 它接受任意个定位参数。
❷ 这行代码可用, 是因为 clocked 的闭包中包含自由变量 func。
❸ 返回内部函数, 取代被装饰的函数。 示例 7-16 演示了 clock 装饰器
的用法。

@clock
def factorial(n):

等价于

factorial = clock(factorial)

在示例中, factorial 会作为 func 参数传给 clock。 然后, clock 函数会返回 clocked 函数, Python 解释器在背后会把 clocked 赋值给 factorial。 其实,查看 factorial 的 name 属性, 会得到
如下结果:

   print(factorial.__name__)
   clocked

所以, 现在 factorial 保存的是 clocked 函数的引用。 自此之后, 每
次调用 factorial(n), 执行的都是 clocked(n)。 clocked 大致做了
下面几件事。
(1) 记录初始时间 t0。
(2) 调用原来的 factorial 函数, 保存结果。
(3) 计算经过的时间。
(4) 格式化收集的数据, 然后打印出来。
(5) 返回第 2 步保存的结果。
这是装饰器的典型行为: 把被装饰的函数替换成新函数, 二者接受相同
的参数, 而且(通常) 返回被装饰的函数本该返回的值, 同时还会做些
额外操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时空无限

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值