python04-装饰器

装饰器

  • 一个产品由多个部门协作开发,如分为底层开发和业务开发

    • 底层开发:主要负责系统底层的调用,方法大概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')

你可能感兴趣的:(python04-装饰器)