装饰器
-
一个产品由多个部门协作开发,如分为底层开发和业务开发
- 底层开发:主要负责系统底层的调用,方法大概100来个
- 业务开发:调用底层开发部门提供的方法,扩展出上千个方法跑业务逻辑
-
如果某天老板要求需要在底层的方法都加上某个功能,可能需要把100来个方法都做修改,耗时10天
- 但是改完后老板发现这样不好,需要还原,这样就GG了,又要改回来,说不定还会把代码改乱
- 一个优化的方法是,在100来个方法内调用一个外部函数,在外部函数里面添加逻辑,但是这样做有一个弊端,当项目不断交接,不同的开发人员对底层核心代码操作,到最后,代码会越来越乱,所以可以用装饰器对代码进行修改,不需要修改底层代码,又不需要业务开发人员修改调用方式
装饰设计模式,但是调用的是装饰后的函数,python的装饰器会覆盖原来的函数,调用的时候,函数名不变,大大减少了代码的修改,提高扩展性
def f1():
print('这个是原始的函数')
def f2(fun):
print('-----------function2----------start')
fun()
print('-----------function2-----------end')
f2(f1)
# 定义装饰器
def outer(fun):
def inner(): # 定义函数inner
print('inner start')
fun()
print('inner end')
return inner # 返回函数inner
# 使用装饰器
@outer
def fun1():
print('HelloWorld')
# 原函数调用不变
fun1()
====== >>
inner start
HelloWorld
inner end
-
原理:
- 执行outer函数,并将原函数作为参数传入outer函数
- 将outer函数的返回值重新赋值给原函数,并覆盖原函数
- 如果返回一个inner函数,则原函数名不变,函数体为inner函数的函数体
- 如果返回的是一个值,则原函数名指向的是一个值,变成一个变量
- 类似:将原函数作为参数封装在另一个函数内,形成新的函数
- 只要函数应用的装饰器,原函数就被重新定义,重定义为装饰器内的函数
传参:如果原函数有参数,则装饰器返回的参数需要和原函数一样,这样才能保证原调用者不需要修改代码,同时,在装饰器内,原函数能够正常调用。
def outer(fun):
def inner(string):
print('inner')
fun(string)
print('inner')
return inner
@outer
def fun(string):
print('fun', string)
fun('string')
- 如果多个函数需要相同的操作,几十个底层函数需要同的功能,如果每一个都要写一个装饰器,这样代码量太大,可以考虑装饰器复用,但是未必所有函数的参数需要的类型和个数相同,这就需要林另外加判断了,比较麻烦
- 但是python内部已经帮我们做好了优化
- fun(*args, **kwargs)作为内部调用函数的参数
def outer(fun):
def inner(*args, **kwargs):
print('inner')
fun(*args, **kwargs)
print('inner')
return inner
@outer
def fun1(num1, num2):
print(num1 + num2)
fun1(100, 200)
- 一个函数调用多个装饰器
- 一个函数可以有多个装饰器
- 应用:某东页面查看订单,需要先登陆,很多地方都需要先登陆才能查看,所以通过装饰器在查看详情前登陆
- 登陆后,用户有普通用户,白金,vip等不同等级的用户,再此基础上在叠加装饰器
- 执行循序是从下网上:outer3-->outer1-->outer2
def outer2(fun):
def inner(*args, **kwargs):
print('装饰器嵌套')
fun(*args, **kwargs)
return inner
def outer1(fun):
def inner(*args, **kwargs):
print('inner')
fun(*args, **kwargs)
print('inner')
return inner
def outer3(fun):
def inner(*args, **kwargs):
fun(*args, **kwargs)
print('outer3')
return inner
@outer2
@outer1
@outer3
def fun(string):
print('fun', string)
fun('string')