一,什么是装饰器?

装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象

装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。

二,装饰器的形成过程。

现在我有一个需求,我想让你测试这个函数的执行时间,在不改变这个函数代码的情况下:

import time

def func1():
print('in func1') def timer(func):
start = time.time()
func()
print(time.time() - start) timer(func1)

上面的代码输出了func1()函数的运行时间,但是我们计算func1()函数的运行时间时,需要调用的是timer(func)函数

有没有办法直接调用func1()函数就能计算func1()函数运行时间呢?

如果让 func1 = timer 呢? 可是timer()函数需要一个函数参数,而我们的 func1 是不需要参数的,显然不行

那该怎么实现呢? 换个思路, timer不能赋值给func1,但是我们可以给timer指定一个函数返回值,将他赋值给func1

那么执行 func1() 时就相当于执行 这个用来赋值的函数.而这个函数在timer()函数内,可以调用timer()函数的参数func

如下所以,我们使用闭包的方法解决了这个问题

import time    # 引入时间模块

def func1():    # 要测试执行时间的函数
print('in func1') def timer(func):
def inner():
start = time.time()
func()
print(time.time() - start)
return inner func1 = timer(func1) # time()的返回值是inner
func1() # func1()==inner()

在上面的方法中,timer()函数就是我们的装饰器函数,func1()是被装饰的.

但是,在上面的例子中,func1()是没有返回值和参数的,要是带上参数返回值呢?

import time    # 引入时间模块

def func1(a,b=1):    # 要测试执行时间的函数
print('in func1')
return 'func1的返回值' def timer(func):
def inner(*args,**kwargs): # 设置为可以接受任意参数
start = time.time()
set = func(*args,**kwargs)
print(time.time() - start)
return set # 返回func函数原本的返回值
return inner func1 = timer(func1) # time()的返回值是inner
func1(a,b=3) # func1(a,b=3)==inner(a,b=3)

但是如果有多个函数,我都想让你测试他们的执行时间,你每次是不是都得func1 = timer(func1)?这样还是有点麻烦,因为这些函数的函数名可能是不相同,有func1,func2,graph,等等,所以更简单的方法,python给你提供了,那就是语法糖。

@timer   # == func1 = timer(func1)

上面的装饰器已经非常完美了,但是有我们正常情况下查看函数信息的方法在此处都会失效:

def index():
'''这是一个主页信息'''
print('from index') print(index.__doc__) #查看函数注释的方法
print(index.__name__) #查看函数名的方法

如何解决这个问题呢?

from functools import wraps

def deco(func):
@wraps(func) #加在最内层函数正上方
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
return wrapper @deco
def index():
'''哈哈哈哈'''
print('from index') print(index.__doc__)
print(index.__name__)

三,开放封闭原则。

1.对扩展是开放的

    为什么要对扩展开放呢?

    我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。

2.对修改是封闭的

    为什么要对修改封闭呢?

    就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。

装饰器完美的遵循了这个开放封闭原则。

四,装饰器的主要功能和固定结构。

def timer(func):
def inner(*args,**kwargs):
'''执行函数之前要做的'''
re = func(*args,**kwargs)
'''执行函数之后要做的'''
return re
return inner
from functools import wraps

def deco(func):
@wraps(func) #加在最内层函数正上方,确保查看函数信息的方法可用
def wrapper(*args,**kwargs):
'''执行函数之前要做的'''
re = func(*args,**kwargs)
'''执行函数之后要做的'''
return re
return wrapper

装饰器的固定格式--wraps版

五,带参数的装饰器。

注意@outer(False)的用法

上面的@timer   相当于   func = timer(func)  ,  返回值是 inner

下面的@outer(False)   相当于  func = outer(False)(func)  ,返回值仍是 inner

def outer(flag):
def timer(func):
def inner(*args,**kwargs):
if flag:
print('''执行函数之前要做的''')
re = func(*args,**kwargs)
if flag:
print('''执行函数之后要做的''')
return re
return inner
return timer @outer(False) #此处相较上面的语法糖,多了括号和参数.@outer(False)==>func=outer(False)(func),返回值仍是inner
def func(): 
print(111) func()

六,多个装饰器装饰一个函数。

def wrapper1(func):
def inner():
print('wrapper1 ,before func')
func()
print('wrapper1 ,after func')
return inner def wrapper2(func):
def inner():
print('wrapper2 ,before func')
func()
print('wrapper2 ,after func')
return inner @wrapper2
@wrapper1
def f():
print('in f') f()

day11 python之函数装饰器的更多相关文章

  1. python基础—函数装饰器

    python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...

  2. Day11 Python基础之装饰器(高级函数)(九)

    在python中,装饰器.生成器和迭代器是特别重要的高级函数   https://www.cnblogs.com/yuanchenqi/articles/5830025.html 装饰器 1.如果说装 ...

  3. python基础-----函数/装饰器

    函数 在Python中,定义一个函数要使用def语句,依次写出函数名.括号.括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回. 函数的优点之一是,可以将代码块与主程 ...

  4. Decorator——Python初级函数装饰器

    最近想整一整数据分析,在看一本关于数据分析的书中提到了(1)if __name__ == '__main__' (2)列表解析式 (3)装饰器. 先简单描述一下前两点,再详细解说Python初级的函数 ...

  5. python 复习函数 装饰器

    # 函数 —— 2天 # 函数的定义和调用 # def 函数名(形参): #函数体 #return 返回值 #调用 函数名(实参) # 站在形参的角度上 : 位置参数,*args,默认参数(陷阱),* ...

  6. python 匿名函数&装饰器

    匿名函数 关键字lambda表示匿名函数,冒号前面的x表示函数参数匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果. >>> list(map(l ...

  7. python闭包函数&装饰器

    一.函数引用 函数可以被引用 函数可以被赋值给一个变量 def hogwarts(): print("hogwarts") # hogwarts() # 函数调用 print(ho ...

  8. Python之函数装饰器

    在实际中,我们可能需要在不改变函数源代码和调用方式的情况下,为函数添加一些新的附加功能,能够实现这种功能的函数我们将其称之为装饰器.装饰器本质上其实还是是一个函数,用来装饰其它函数,为函数添加一些附加 ...

  9. python 之 函数 装饰器

    5.8 装饰器 1 开放封闭原则 软件一旦上线后,就应该遵循开放封闭原则,即对修改源代码是封闭的,对功能的扩展是开放的 也就是说我们必须找到一种解决方案: 能够在不修改一个功能源代码以及调用方式的前提 ...

随机推荐

  1. Android 8 设置蓝牙名称 流程

    记录android 8设置蓝牙名称的流程. packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDeviceRenam ...

  2. laravel5.8笔记十:Redis操作

    > 位置:\vendor\laravel\framework\src\Illuminate\Redis\Connections\PhpRedisConnection.php > 参考:ht ...

  3. 【深入Java虚拟机】一 JVM类加载过程

    首先Throws(抛出)几个自己学习过程中一直疑惑的问题: 1.什么是类加载?什么时候进行类加载? 2.什么是类初始化?什么时候进行类初始化? 3.什么时候会为变量分配内存? 4.什么时候会为变量赋默 ...

  4. java多线程的3种写法

    1.Thread /** * */ package testJava2.thread; /** * @author xxx.sjtu * @function * @date 2017年5月17日 * ...

  5. count(1)、count(*)与count(列名)的执行区别

    执行效果: 1.  count(1) and count(*) 当表的数据量大些时,对表作分析之后,使用count(1)还要比使用count(*)用时多了! 从执行计划来看,count(1)和coun ...

  6. 【CF434E】Furukawa Nagisa's Tree 点分治

    [CF434E]Furukawa Nagisa's Tree 题意:一棵n个点的树,点有点权.定义$G(a,b)$表示:我们将树上从a走到b经过的点都拿出来,设这些点的点权分别为$z_0,z_1... ...

  7. PHP实现今天是星期几

    echo "今天是星期" . mb_substr( "日一二三四五六",date("w"),1,"utf-8" );

  8. Javascript 异步处理与计时跳转

    实现计时跳转的代码: <html lang="en"> <head> <meta charset="UTF-8"> < ...

  9. 15 VScode 使用相关

    1.生成html头文件 ①:按下!键 ②:连按两下tab键  即可

  10. vim 命令补充(1)

    本篇文章主要教你如何使用 Vim 分屏功能. 分屏启动Vim 使用大写的O参数来垂直分屏. vim -On file1 file2 ... 使用小写的o参数来水平分屏. vim -on file1 f ...