简介

定义:装饰器是特殊的闭包,特殊在于装饰器的参数除了可以是基本数据类型外,还可以是函数或类
作用:不改动原函数、不改变原函数调用方式的前提下,扩展函数功能,遵循了开放封闭原则

函数装饰器

需求一

为源码函数扩展功能,且不改变调用方式

版本一

  1. # v1
  2. def login(func):
  3. print("passer user vertification...")
  4. return func # func是原tv()函数
  5. def tv():
  6. print("Welcome to tv page")
  7. tv = login(tv)
  8. # tv的值为tv函数的内存地址,这里把tv函数当作变量传给login函数,属于高阶函数操作
  9. tv()

注解:想给tv()函数加个功能login(),但是我不想改变原函数的调用方式,调用方式依然是tv()

  1. # v1.1:换成装饰器
  2. def login(func):
  3. print("passer user vertification...")
  4. return func # func是原tv()函数
  5. @login # @login等效于tv = login(tv)
  6. def tv():
  7. print("Welcome to tv page")
  8. tv()

注解:v1.1把语法换成装饰器后,等效于上v1

版本二

被加入的功能函数login变成闭包

  1. # v2
  2. def login(func):
  3. def inner():
  4. print("passed user vertification...")
  5. func() # func是原tv()函数
  6. return inner
  7. def tv():
  8. print("Welcome to tv page")
  9. tv = login(tv)
  10. tv()

等效于

  1. # v2.1
  2. def login(func):
  3. def inner():
  4. print("passed user vertification...")
  5. func() # func是原tv()函数
  6. return inner
  7. @login # @login等效于tv = login(tv)
  8. def tv():
  9. print("Welcome to tv page")
  10. tv()

注解:演示到这里,貌似差不多了,剩下的就是把参数传进去和返回回来

需求二

版本三

需求一 + 传递参数 + 返回值

  1. # v3.1
  2. # func无返回值+普通参数
  3. def login(func):
  4. def inner(args): # 参数其实传到了这里
  5. print("passed user vertification...")
  6. func(args) # func是原tv()函数
  7. return inner
  8. @login # @login等效于tv = login(tv)
  9. def tv(name):
  10. print("Welcome [%s] to tv page" % name)
  11. tv('hy') # 传入参数

参数太死了,不够灵活,改成动态参数*args, **kwargs

  1. # v3.2
  2. # func无返回值+动态参数
  3. def login(func):
  4. def inner(*args, **kwargs): # 参数其实传到了这里
  5. print("passed user vertification...")
  6. func(*args, **kwargs) # func是原tv()函数
  7. return inner
  8. @login # @login等效于tv = login(tv)
  9. def tv(name):
  10. print("Welcome [%s] to tv page" % name)
  11. tv('hy') # 传入参数

那我想获取返回值怎么办?inner()函数加个return func

  1. # v3.3 推荐版本
  2. # func有返回值+动态参数
  3. def login(func):
  4. def inner(*args, **kwargs): # 参数其实传到了这里
  5. print("passed user vertification...")
  6. return func(*args, **kwargs) # func是原tv()函数
  7. return inner
  8. @login # @login等效于tv = login(tv)
  9. def tv(name):
  10. print("Welcome [%s] to tv page" % name)
  11. return 6 # 有返回值
  12. res = tv('hy') # 传入参数
  13. print(res) # 6

这里,已经把装饰器的原理和常用用法阐述清楚了,如果遇到更复杂的装饰器,也是可以理解并加以运用的

最终版本

顺便说一下,装饰器的应用场景,一般就是在原函数的前面或者后面加上自定义代码,比如登录前的登录模块代码,那我想再 登录、看完电视后,还想睡觉怎么办,你这里只在前面加了代码啊

  1. # 最终版
  2. # func有返回值+动态参数
  3. def outer(func):
  4. def inner(*args, **kwargs): # 参数其实传到了这里
  5. print("前面的代码") # 可替换成任意类型的代码:单行或多行代码、函数、类等
  6. res = func(*args, **kwargs) # func是原tv()函数
  7. print("后面的代码") # 替换成任意类型的代码:单行或多行代码、函数、类等
  8. return res
  9. return inner
  10. @outer # @login等效于tv = login(tv)
  11. def tv(name):
  12. print("Welcome [%s] to tv page" % name)
  13. return 6 # 有返回值
  14. res = tv('hy') # 传入参数
  15. print(res) # 6