python--装饰器

python装饰器学了几篇,比较难理解,特写此博客分析装饰器原理和实例:

一、装饰器概念

python装饰器就是用于拓展被装饰函数功能的一种函数(一般是高阶函数,接受被装饰器函数当做参数传入),这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改被装饰函数的代码前提下给函数增加新的功能。

二、实例

需求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.024060487747192383

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

2. 最简单的装饰器

import time

def decorator(fun):
def 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")
do_something()

结果如下:

play game
0.023060321807861328

装饰器是在函数定义时前面加@,然后跟装饰器的实现函数。可以看出,现在只要直接调用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("hahaha")

结果如下:

play game hahaha
0.024062395095825195

实现很简单, 就是给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("hahaha")
do_something2("gebilaowang", "hahaha")

结果如下:

play game hahaha
0.0240633487701416
gebilaowang play game hahaha
0.02406454086303711

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

5. 让装饰器带参数

import time

def decorator(max):
def _decorator(fun):
def wrapper(*args, **kwargs):
start = time.time()
for i in range(max):
fun(*args, **kwargs)
runtime = time.time()-start
print(runtime)
return wrapper
return _decorator

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

结果如下:

play game hahaha
play game hahaha
play game hahaha
0.07122611999511719

三. 原理

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调用之前的时候执行的。

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()
结果如下:

File "C:/Users/xudachen/PycharmProjects/Python全栈开发/第二模块/导师考核/test.py", line 18, 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("hahaha")

结果如下:

Traceback (most recent call last):
File "C:/Users/xudachen/PycharmProjects/Python全栈开发/第二模块/导师考核/test.py", line 19, in <module>
do_something("hahaha")
TypeError: wrapper() takes 0 positional arguments but 1 was given

3 带参数的装饰器

@decomaker(argA, argB, ...)

def func(arg1, arg2, ...):

pass

#这个式子相当于 func = decomaker(argA, argB, ...)(func)

先写到这里

参考博客:

http://blog.csdn.net/TangHuanan/article/details/45094497

原文地址:https://www.cnblogs.com/xudachen/p/8556218.html