本节内容
一、装饰器导引 |
1、函数对象特性
#### 第一波 #### def foo(): # 表示定义函数 print('foo') # 表示函数体 foo #表示是函数名,指向函数体的地址 foo() #表示执行foo函数 #### 第二波 #### def foo(): print('foo') foo = lambda x: x + 1 foo() # 执行下面的lambda表达式,而不再是原来的foo函数,因为函数 foo 被重新定义了 #### 第三波 #### def now(): print('2017-01-12') f = now f() # 执行结果 2017-02-12 # 函数也是一个对象,而且函数对象也可以被赋值给变量,所以通过该变量也能调用该函数
2、扩展业功能需求
初创公司有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,如:数据库操作、redis调用、监控API等功能。
业务部门使用基础功能时,只需调用基础平台提供的功能即可。如下:
############### 基础平台提供的功能如下 ############### def f1(): print('f1') def f2(): print('f2') def f3(): print('f3') def f4(): print('f4') ############### 业务部门A 调用基础平台提供的功能 ############### f1() f2() f3() f4() ############### 业务部门B 调用基础平台提供的功能 ############### f1() f2() f3() f4()
目前公司有条不紊的进行着,但是,以前基础平台的开发人员在写代码时候没有关注验证相关的问题,即:基础平台的提供的功能可以被任何人使用。
现在需要对基础平台的所有功能进行重构,为平台提供的所有功能添加验证机制,即:执行功能前,先进行验证。
3、各种解决方案
员工一,他是这么做的:
跟每个业务部门交涉,每个业务部门自己写代码,调用基础平台的功能之前先验证。诶,这样一来基础平台就不需要做任何修改了。
当天他被开除了。
员工二,他是这么做的:
只对基础平台的代码进行重构,让N业务部门无需做任何修改
1 ############### 基础平台提供的功能如下 ############### 2 3 def f1(): 4 # 验证1 5 # 验证2 6 # 验证3 7 print('f1') 8 9 def f2(): 10 # 验证1 11 # 验证2 12 # 验证3 13 print('f2') 14 15 def f3(): 16 # 验证1 17 # 验证2 18 # 验证3 19 print ('f3') 20 21 def f4(): 22 # 验证1 23 # 验证2 24 # 验证3 25 print ('f4') 26 27 ############### 业务部门不变 ############### 28 ### 业务部门A 调用基础平台提供的功能### 29 30 f1() 31 f2() 32 f3() 33 f4() 34 35 ### 业务部门B 调用基础平台提供的功能 ### 36 37 f1() 38 f2() 39 f3() 40 f4()
过了一周,他被开除了
员工三,他是这么做的:
只对基础平台的代码进行重构,其他业务部门无需做任何修改
1 ############### 基础平台提供的功能如下 ############### 2 3 def check_login(): 4 # 验证1 5 # 验证2 6 # 验证3 7 pass 8 9 10 def f1(): 11 12 check_login() 13 14 print('f1') 15 16 def f2(): 17 18 check_login() 19 20 print('f2') 21 22 def f3(): 23 24 check_login() 25 26 print('f3') 27 28 def f4(): 29 30 check_login() 31 32 print('f4')
战战兢兢,员工三保留了工作,进一步观察,哎工作不易啊
最终大BOSS给了解答:
写代码要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,
但可以被扩展,即:
- 封闭:已实现的功能代码块,不能被修改
- 开放:扩展已实现的代码功能块
如果将开放封闭原则应用到上述需求中,那么就不允许在函数f1、f2、f3、f4的内部进行修改代码,大BOSS给了如下一个实现方案
def w1(func): def inner(): # 验证1 # 验证2 # 验证3 return func() return inner @w1 def f1(): print('f1') @w1 def f2(): print('f2') @w1 def f3(): print('f3') @w1 def f4(): print('f4)
对于上述代码,也是仅仅对基础平台的代码进行修改,就可以实现在其他人调用函数f1、f2、f3、f4之前都进行【验证】,
并且其他业务部门无需做任何的操作。内部的实现原理就是装饰器
二、装饰器解析 |
1、装饰器基本概念
A 装饰器定义:本质是函数,功能是为其他函数添加新功能
B 遵循原则:
不修改被修饰函数的源代码
为被装饰函数添加新功能后,不修改被修饰函数的调用方式
C 分解装饰器:装饰器 = 高阶函数 + 函数嵌套 + 闭包
其中一个函数参数为函数名,或者函数的返回值是一个函数名,这样的函数称之为高阶函数
2、无参装饰器解析
单独以f1为例:
# 定义装饰器 def w1(func): def inner(): # 验证功能 print('我是为函数 %s 添加的验证模块' % func.__name__) return func() return inner # @w1为Python的语法糖,下面一段代码本质执行f1 = w1(f1) @w1 def f1(): # 不修改被修饰函数的源代码 print('调用f1功能') f1() # 不修改被修饰函数的调用方式
程序从上到下依次执行
(一) def w1(func): # 将函数w1加载到内存,未执行w1函数体
(二) @w1 # @函数名,Python一种语法糖,等价于 f1 = w1(f1),其中参数f1被保存下来。所以@w1内部执行如下
执行w1()函数体,参数为f1:
def inner(): # 将函数inner加载到内存,未执行inner函数体
return inner
以上操作完成 函数f1 = w1(f1),无论原先函数f1,还是被重构inner()重构的函数f1,皆未被执行
(三) f1() # 执行函数被重构的f1()函数体,也就是执行函数 inner():
print('我是为函数 %s 添加的验证模块' % func.__name__)
return func():调用原函数 f1(),也就是 print('调用f1功能')
3、有参装饰器解析