越来越觉得写一点技术博客是有多么重要了,明日复明日,现在就开始写吧!

1. 普通装饰器

  装饰器的写法是一种语法糖,装饰器也还是一个函数而已,它接收一个函数对象作为参数,并返回一个新函数,主要是拓展原函数功能,在不改变原函数代码结构的情况下附加操作达到业务需求。比如做身份认证、访问记录等预处理操作,或者是日志记录、通道关闭等收尾操作,又或者是性能测试这种前后都附加代码的操作。

  直接就上一个的基本的装饰器代码  (用print语句代替功能实现)

def deco(fun):
def inner(*args,**kwargs):
print('Successful authentication') # 预处理操作,验证身份
fun(*args,**kwargs) # 原操作
return inner @deco
def func(*args,**kwargs):
print(args,kwargs)  func(1,2,a=3)
# Perform pretreatment
# (1, 2) {'a': 3}

  当调用func时,伪流程就是:

    1. 先记录了func接收的参数们的内存地址

    2. 将func函数对象作为参数传入来调用deco,执行时将参数func绑定到inner函数对象上,返回inner函数对象

    3. 调用inner函数,传入之前记录的参数们,执行预操作(验证身份)

    4. 调用func函数,传入inner接收的参数们,执行原操作

  相当于合成并调用了一个新函数,新函数里调用了旧函数。但是好像我们去掉装饰器这个标记语法糖,还原为两个正常的函数,也能实现上面的逻辑吧:

def deco(fun):
def inner(*args,**kwargs):
print('Successful authentication') # 预处理操作,验证身份
fun(*args,**kwargs)  # 原操作
return inner def func(*args,**kwargs):
print(args,kwargs)  

new_fun = deco(func)
  new_fun(1,2,a=3)
  # Perform pretreatment
  # (1, 2) {'a': 3}

  但真实的流程是装饰器在文件载入的时候,就已经处理了被装饰器标记的函数,也就是说当文件载入时,所有被标记的函数都已经变成了装饰器返回的函数了(各自信息唯一),当调用的时候也就直接调用的此函数了。

2.装饰链

  也就是多层装饰器嵌套了一下

def deco1(fun):
def inner1(*args,**kwargs):
print('Successful authentication') # 预处理操作,验证身份
fun(*args,**kwargs)
return inner1 def deco2(fun):
def inner2(*args,**kwargs):
print('Successful access record') # 预处理操作,访问记录
fun(*args,**kwargs)  # 原操作
return inner2 @deco1
@deco2
def func(*args,**kwargs):
print(args,kwargs) func(1,2,a=3)
# Perform pretreatment
# (1, 2) {'a': 3}

  需要注意的是包装顺序,距离最远的是最外层的包装,就像穿的衣服一样,要先穿贴身的内衣,然后才是外套什么的

  此时调用func时,基本的流程就是:

    1. 记录了func接收的参数们的内存地址

    2. 将func函数对象作为参数传入来调用deco2,执行时将参数func绑定到inner2函数对象上,返回inner2函数对象

    3. 将inner2函数对象作为参数传入来调用deco1,执行时将参数inner2绑定到inner1函数对象上,返回inner1函数对象

    4. 调用inner1函数,传入之前记录的参数们,执行预操作1(验证身份)

    5. 调用inner2函数,传入inner1接收的参数们,执行预操作2(访问记录)

    6. 调用func函数,传入inner2接收的参数们,执行原操作

3.类装饰器

类的__call__方法可以让类实例可以像函数一样调用,所以跟普通的区别不大

class Deco(object):
def __init__(self, fun):
self.fun = fun
def __call__(self,*args,**kwargs):
print("Successful authentication") # 预处理 身份验证
self.fun(*args,**kwargs) @Deco
def func(*args,**kwargs):
print("func") func(1,2,a=3)
# Perform pretreatment
# (1, 2) {'a': 3}

4. 装饰器参数

  利用闭包绑定了参数

def deco_param(*dargs,**dkwargs)
def deco(fun):
def inner(*args,**kwargs):
print('deco_param:',dargs,dkwargs) # 打印装饰器参数
print('Successful authentication') # 预处理操作,验证身份
fun(*args,**kwargs)
return inner
return deco @deco(4,b=5)
def func(*args,**kwargs):
print(args,kwargs)  # 原操作 func(1,2,a=3)
# Perform pretreatment
# (1, 2) {'a': 3}

  

5.wraps恢复原函数信息

 按照之前的第一个装饰器例子,打印原函数名,发现被装饰的函数信息已经被丢失,变成了装饰器返回的函数的信息

def deco(fun):
def inner(*args,**kwargs):
print('Successful authentication') # 预处理操作,验证身份
fun(*args,**kwargs)
return inner @deco
def func(*args,**kwargs):
print(args,kwargs)  # 原操作
print(func.__name__)  
# inner

  要想恢复函数之前的信息,那么就需要用上functools包,在闭包函数上加上一个带参的装饰器,逻辑上只是加长了装饰链,而这个装饰器的拓展功能正是找回原函数(多层装饰器中可以是上一个装饰器的返回函数)的信息

from functools import wraps
def deco(fun):
  @wraps(fun)
def inner(*args,**kwargs):
print('Successful authentication') # 预处理操作,验证身份
fun(*args,**kwargs)
return inner @deco
def func(*args,**kwargs):
print(args,kwargs)  # 原操作 print(fun.__name__)
# func

  ps:一般情况不用找回函数信息,但在使用flask时,flask中不允许接口函数重名导致覆盖或被覆盖,如果有多个接口使用同一个装饰器的话,正常情况下接口函数信息就都为装饰器中的闭包函数信息,这样flask会报AssertionError: View function mapping is overwriting an existing endpoint function xx.inner的错误,此时就可以用上functools的wraps装饰器来找回原函数信息了。而flask必带的接口装饰器route查看源码似乎没有用到wraps,但是肯定也是做了处理的。

以上就是一些装饰器的介绍,如有错误,还请指出-----1738268742@qq.com

python_装饰器的更多相关文章

  1. python_装饰器_语法糖

    什么是高阶函数? -- 把函数名当做参数传给另外一个函数,在另外一个函数中通过参数调用执行 #!/usr/bin/python3 __author__ = 'beimenchuixue' __blog ...

  2. Python_装饰器进阶_32

    #带参数的装饰器 #500个函数 import time FLAGE = True def timmer_out(flag): def timmer(func): def inner(*args,** ...

  3. Python_装饰器习题_31

    # 1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件), # 要求登录成功一次,后续的函数都无需再输入用户名和密码 FLAG = False def login(func): def ...

  4. Python_装饰器复习_30

    复习: # 装饰器的进阶 # functools.wraps # 带参数的装饰器 # 多个装饰器装饰同一个函数# 周末的作业 # 文件操作 # 字符串处理 # 输入输出 # 流程控制 # 装饰器# 开 ...

  5. Python_装饰器_29

    # 装饰器形成的过程 : 最简单的装饰器 有返回值的 有一个参数 万能参数 # 装饰器的作用 # 原则 :开放封闭原则 # 语法糖 :@ # 装饰器的固定模式 import time # print( ...

  6. python_装饰器模式

    装饰器模式定义:动态地给一个对象添加一些额外的职责. 在Python中Decorator mode可以按照像其它编程语言如C++, Java等的样子来实现,但是Python在应用装饰概念方面的能力上远 ...

  7. Python_装饰器、迭代器、生成器

    一.装饰器 装饰器的存在是为了实现开放封闭原则: 封闭: 已实现的功能代码块不应该被修改: 开放: 对现有功能的扩展开放. 理解装饰器的三要素: 函数的作用域 高阶函数 闭包 1. 闭包 闭包定义:如 ...

  8. python_装饰器——迭代器——生成器

    一.装饰器 1.什么是装饰器? 器=>工具,装饰=>增加功能 1.不修改源代码 2.不修改调用方式 装饰器是在遵循1和2原则的基础上为被装饰对象增加功能的工具 2.实现无参装饰器 1.无参 ...

  9. Python_装饰器函数

    楔子 作为一个会写函数的python开发,我们从今天开始要去公司上班了.写了一个函数,就交给其他开发用了. def func1(): print('in func1') 季度末,公司的领导要给大家发绩 ...

随机推荐

  1. AssetBundle-----资源包划分

    资源包划分 经常更新的资源放在一个单独的包里面,跟不经常更新的包分离;需要同时加载的资源放在一个包里面;其他包共享的资源放在一个单独的包里面;需要同时加载的小资源打包成一个包;对于一个同一个资源有两个 ...

  2. 科学计算和可视化(numpy及matplotlib学习笔记)

    网上学习资料:https://2d.hep.com.cn/1865445/9 numpy库内容: 函数 描述 np.array([x,y,z],dtype=int) 从Python列表和元组创造数组 ...

  3. centos6.5-VMware虚拟机-双网卡绑定

    1 添加多张网卡(生产环境中有多个卡槽,可用ifconfig查看) 2 编辑两张虚拟机的网卡和物理机的连接方式,这里两张都使用NAT即可 3 打开虚拟机查看所有的网卡(网络接口),修改配置网卡配置文件 ...

  4. CS萌新的汇编学习之路(其实是老师作业呵呵哒)Learning of Assembly Language

    第一节课学习汇编语言,做笔记,做笔记 1.概念 首先是汇编语言这门课程的定义以及对于学习高级语言.深入理解计算机系统的作用 软硬件接口机器语言 汇编语言 高级语言 关系 机器语言和汇编语言可移植性差 ...

  5. JavaException的使用

    (第一个文件 MyException.java) package exception;import java.io.*; //先创建自己的异常类继承与Exception的类 public class ...

  6. DevExpress中GridControl的使用笔记(转)

    转自:https://www.jianshu.com/p/badc1d2f0841 注:练习例子为: DxApplication1 -> XtraForm1 , 例子上传到本博中 2019.4. ...

  7. 2019.4.24 一题(CF 809E)——推式子+虚树

    题目:http://codeforces.com/contest/809/problem/E

  8. tomcat 闪退问题排查

    由于启动tomcat回出现闪退情况,看不到异常 解决方法: 一. 打开startup.bat文件,在最下面 在文本的最后敲上pause,保存后重新运行startup.bat,这时候窗口会留在桌面上(调 ...

  9. 一个极其简易版的vue.js实现

    前言 之前项目中一直在用vue,也边做边学摸滚打爬了近一年.对一些基础原理性的东西有过了解,但是不深入,例如面试经常问的vue的响应式原理,可能大多数人都能答出来Object.defineProper ...

  10. PRBS

    PRBS是Pseudo Random Binary Sequence的缩写,即“伪随机二进制序列”的意思.PRBS码具有“随机”特性,是因为在PRBS码流中,二进制数“0”和“1”是随机出现的,但是它 ...