7.装饰器讲解系列之原理用法(上)

2022-04-26  本文已影响0人  软件开发技术修炼
最全装饰器知识点

1、什么是装饰器

本质上增强函数或类的功能的一个函数;
通俗来讲,装饰器可以让一个Python函数拥有原本没有的功能,可以通过装饰器,变的强大漂亮。
【比如孙悟空,通过炼丹炉、龙宫、拜师而获得火眼金睛、金箍棒、七十二变,而变得很厉害;但它始终是猴子(函数本身)】

装饰器的几点属性:
实质:是一个函数
参数:是你要装饰的函数名(并非函数调用)
返回:是装饰完的函数名(并非函数调用)
作用:为已经存在的对象添加额外的功能
特点:不需要对对象做任何的代码上的变动

python中装饰器是随着程序的加载运行而自动加载的,跟调不调用方法没有关系.所以只要是装饰器内部函数以外的部分都会自动加载执行,不用调用。

2、为何引入装饰器

实例一:

一个简单的函数,增加其他属性,但不影响原代码

#孙悟空吃桃子
def sun():
    print('eat peach')
sun()

# 想增加一个sun可以有火眼金睛,不破坏原代码基础上
def lian_dan(func):
    def change(*args,**kwargs):
        print("火眼金睛")
        return func(*args,**kwargs)
    return change

@lian_dan   
# 引用装饰器(把下面的孙放进炼丹炉里,并把新的复制给下方函数)
def sun():
    print('eat peach')

sun()
#结果:
火眼金睛
eat peach

-----------不使用装饰器----------
def sun():
    print('eat peach')

new_sun = lian_dan(sun())    #放入材料,原来孙悟空将方案给新的孙悟空
sun()    #执行炼丹程序,新孙悟空出世
实例二:

不影响原代码基础上,增加权限


def play():
    print('开始播放"孙悟空')

play()

userAge = 50
def canYou(func):
    def decorator(*args,**kwargs):
        # 加权限认证  
        if userAge > 1 and userAge < 10:
            return func(*args,**kwargs)
        print('your age is not right')
    return decorator

@canYou
def play():
    print('开始播放"孙悟空')

play()
# 结果:
your age is not right
实例三:

一次性在一个函数上用多个装饰器,代码执行顺序,从内到外

def lian_dan(func):
    def change(*args,**kwargs):
        print('火眼金睛')
        return func(*args,**kwargs)
    return change

def long(func):
    def hi(*args,**kwargs):
        print('金箍棒')
        return func(*args,**kwargs)
    return hi

def baishi(func):
    def teach(*args,**kwargs):
        print("七十二变")
        return func(*args,**kwargs)
    return teach

@baishi
@long
@lian_dan
def sun():
    print('eat peach')

sun()
#结果:
七十二变
金箍棒
火眼金睛
eat peach
# 代码执行顺序,从内到外

3、装饰器可以解决哪些实际问题

实际应用:用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

比如,需要计算两数相加的时间,两数相减的时间

# 函数
import time

def add(a,b):
  start_time = time.time()
  res = a+b
  exec_time = time.time() - start_time
  return res
使用装饰器

装饰器函数的外部函数传入我要装饰的函数名字,返回经过装饰后函数的名字;内层函数(闭包)负责修饰被修饰函数

import time
# 定义装饰器
def time_calc(func):
  def wrapper(*args, **kargs):
    # 可以自定义传入的参数
    print(func.__name__)
    start_time = time.time()
    f = func(*args, **kargs)
    exec_time = time.time() - start_time
    # 返回传入的方法名参数的调用
    return f
  # 返回内层函数的函数名
  return wrapper

# 使用装饰器
@time_calc
def add(a,b):
  return a+b

@time_calc
def sub(a,b):
  return a-b

add(1,3)
sub(2,9)
运行结果

4、装饰器背后原理

在上面代码中:
1、func是我要装饰器的函数,我想用装饰器显示func函数运行的时间;
2、@decorator这个语法相当于 执行 func = decorator(func),为func函数装饰并返回;
3、装饰器函数 - decorator,该函数的传入参数是func (被装饰函数),返回参数是内层函数;
4、这里的内层函数-wrapper,其实就相当于闭包函数,它起到装饰给定函数的作用,wrapper参数为args, kwargs。args表示的参数以列表的形式传入;kwargs表示的参数以字典的形式传入

def wrapper(*args,**kwargs):
    print("args:", end= ' ')
    print(args)
    print("kwargs:", end=' ')
    print(kwargs)

wrapper(["hi"],123,k = 110,p = 112)
# 结果:
args: (['hi'], 123)
kwargs: {'k': 110, 'p': 112}

5、@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作
如没有使用@time_calc时,调用时,需要加上
tic = time_calc(sub)

6、如果有其他的类似函数,可以继续调用装饰器来修饰函数,而不用重复修改函数或增加新的封装;
归因于 python的函数可像普通对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可作为返回值,可被定义在另外一个函数内

最后,想弄懂装饰器,可先点击学习下之前讲解的 4.闭包
关于装饰器,还有两篇进行讲解,关注我,查看系列文章,完全搞定它!

上一篇 下一篇

猜你喜欢

热点阅读