装饰器学习(2)------深入理解Python 装饰器(decorator)

本文通过多个实例详细介绍了Python装饰器的使用方法及其实现原理,包括如何统计函数执行时间、如何让装饰器带参数等,并深入探讨了装饰器运行机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明来源:http://blog.youkuaiyun.com/TangHuanan/article/details/45094497

刚看到Python装饰器时, 觉得很神奇。简单实验下,发现也就那么回事。但是慢慢的看到越来越多的装饰器。很多时候又不了解到底是怎么回事了。


最后还是决定好好研究下。


先看看一些实例, 然后再来分析下原理 

假设我们有如下的基本函数

def do_something():
    for i in range(1000000):
        pass
    print "play game"

do_something()

结果如下:

play game

需求1: 统计函数的执行时间

1. 不是装饰器的装饰器

import time
def decorator(fun):
    start = time.time()
    fun()
    runtime = time.time()-start
    print runtime

def do_something():
    for i in range(1000000):
        pass
    print "play game"

decorator(do_something)

结果如下:

play game
0.015633821487426758

这种实现看上去还可以,但是每次调用的是decorator,还要把函数作为一个参数传入。这样需要修改调用的地方,使用起来就不方便了


2. 最简单的装饰器

import time
def decorator(fun):
    def inner():
        start = time.time()
        fun()
        runtime = time.time()-start
        print(runtime)
    return inner

@decorator
def do_something():
    for i in range(1000000):
        pass
    print("play game")

do_something()

结果如下:

play game
0.01563405990600586
装饰器是在函数定义时前面加@,然后跟装饰器的实现函数。可以看出,现在只要直接调用do_something就可以了。调用的地方不要作任何修改。


3. 目标函数带固定参数的装饰器

import time
def decorator(fun):
    def wrapper(name):
        start = time.time()
        fun(name)
        runtime = time.time()-start
        print runtime
    return wrapper
@decorator
def do_something(name):
    for i in range(1000000):
        pass
    print "play game " + name

do_something("san guo sha")

结果如下:

play game san guo sha
0.039999961853

实现很简单, 就是给wrapper函数参加相同的参数。

4. 目标函数带不固定参数的装饰器

import time
def decorator(fun):
    def wrapper(*args, **kwargs):
        start = time.time()
        fun(*args, **kwargs)
        runtime = time.time()-start
        print runtime
    return wrapper
@decorator
def do_something(name):
    for i in range(1000000):
        pass
    print "play game " + name

@decorator
def do_something2(user, name):
    for i in range(1000000):
        pass
    print user+" play game " + name

do_something("san guo sha")
do_something2("wang xiao er","san guo sha")

结果如下:

play game san guo sha
0.029000043869
wang xiao er play game san guo sha
0.0310001373291

需求2: 目标函数每次调用重复执行指定的次数

5. 让装饰器带参数

import time
def decorator(max):
    def _decorator(fun):
        def wrapper(*args, **kwargs):
            start = time.time()
            for i in xrange(max):
                fun(*args, **kwargs)
            runtime = time.time()-start
            print runtime
        return wrapper
    return _decorator
@decorator(2)
def do_something(name):
    for i in range(1000000):
        pass
    print "play game " + name

do_something("san guo sha")
结果如下:
play game san guo sha
play game san guo sha
0.0600001811981

6. 原理

看了这么多实例, 装饰器的基本类型也基本上都有了。是不是清楚了呢? 

如果还是不清楚,那就继续看下面的内容。

1 不带参数的装饰器

@a_decorator
def f(...):
    ...

#经过a_decorator后, 函数f就相当于以f为参数调用a_decorator返回结果。
f = a_decorator(f)

来分析这个式子, 可以看出至少要满足以下几个条件 
1. 装饰器函数运行在函数定义的时候 
2. 装饰器需要返回一个可执行的对象 

3. 装饰器返回的可执行对象要兼容函数f的参数

2 验证分析

1 装饰器运行时间
import time
def decorator(fun):
    print "decorator"
    def wrapper():
        print "wrapper"
        start = time.time()
        fun()
        runtime = time.time()-start
        print runtime
    return wrapper
@decorator
def do_something():
    for i in range(1000000):
        pass
    print "play game"

结果如下:

decorator

可以看出, 这里的do_something并没有调用, 但是却打印了decorator, 可wrapper没有打印出来。也就是说decorator是在do_something调用的时候执行的。(由于没有写do_something(),所以没有调用这个函数)

2 返回可执行的对象
import time
def decorator(fun):
    print "decorator"
    def wrapper():
        print "wrapper"
        start = time.time()
        fun()
        runtime = time.time()-start
        print runtime
    return None
@decorator
def do_something():
    for i in range(1000000):
        pass
    print "play game"

do_something()

结果如下:

decoratorTraceback (most recent call last):
  File "deco.py", line 17, in <module>
    do_something()
TypeError: 'NoneType' object is not callable
3 兼容函数f的参数
import time
def decorator(fun):
    print "decorator"
    def wrapper():
        print "wrapper"
        start = time.time()
        fun()
        runtime = time.time()-start
        print runtime
    return wrapper
@decorator
def do_something(name):
    for i in range(1000000):
        pass
    print "play game"

do_something("san guo sha")
结果如下:

http://blog.youkuaiyun.com/TangHuanan/article/details/45094497

太多,不写了







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值