15、装饰器

装饰器储备知识

  1. 名称空间和作用域
  2. *args**kwargs作为形参和实参的作用
  3. 函数对象
  4. 函数嵌套

装饰器(无参装饰器)

  1. 定义:给代码添加额外功能的函数
  2. 作用:在不改变代码调用方式和代码内容的前提下,对代码增加额外的功能
  3. 代码的原则:开放封闭原则。

案例:
阶段一:增加代码执行时间的功能(直接修改了定义阶段函数体代码)
不符合开放封闭原则

import time
def func1(x):
    start=time.time()
    print("my name is %s,welcome to my home" %x)
    time.sleep(2)
    stop=time.time()
    print(stop-start)
func1("lzz")

阶段二:增加代码执行时间的功能(直接修改调用阶段的函数体代码,多处调用都需要修改,代码冗余)
代码写死了,只能对执行时间只对func1起作用

import time
def func1(x):
    print("my name is %s,welcome to my home" %x)
    time.sleep(2)

start=time.time()
func1("lzz")
stop=time.time()
print(stop-start)

阶段三:增加代码执行时间功能(功能写死了,只能对func1做装饰,增加了对原函数的传参,但此时的函数已经不是func1)

import time
def func1(x):
    print("my name is %s,welcome to my home" %x)
    time.sleep(2)

def func2(*args,**kwargs):
    start=time.time()
    func1(*args,**kwargs)
    stop=time.time()
    print(stop-start)
func2()

阶段四:增加代码执行时间功能(可以指定对某函数进行装饰,但是此时的func1已经不是原来定义的func1了,很多属性不同)

import time
def func1(x):
    print("my name is %s,welcome to my home" %x)
    time.sleep(2)

def outter(f):
    def func2(*args,**kwargs):
        start=time.time()
        f(*args,**kwargs)
        stop=time.time()
        print(stop-start)
    return  func2
func1=outter(func1)
func1("lzz")

阶段五:增加代码执行时间功能(使用语法糖,简洁语法)

import time
def outter(f):
    def func2(*args,**kwargs):
        """装饰的函数"""
        start=time.time()
        f(*args,**kwargs)
        stop=time.time()
        print(stop-start)
    return func2

@outter  #等同于 func1=outter(func1) ;语法糖是在被装饰函数的上方添加@装饰器名称
def func1(x):
    """原始函数"""
    print("my name is %s,welcome to my home" %x)
    time.sleep(2)
    
func1("fffafrf")
print(func1,func1.__doc__)

阶段六:增加代码执行时间功能(使用wraps使得被装饰函数和装饰函数的属性完全一样,res同步的被装饰和装饰函数的返回值)
装饰器成功是因为它让被装饰函数的使用者无感知

from functools import wraps
import time
def outter(f):
    @wraps(f)
    def func2(*args,**kwargs):
        """装饰的函数"""
        start=time.time()
        res=f(*args,**kwargs)
        stop=time.time()
        print(stop-start)
        return res
    return func2

@outter  #等同于 func1=outter(func1)
def func1(x):
    """原始函数"""
    print("my name is %s,welcome to my home" %x)
    time.sleep(2)
    return "lzz"
    
res=func1("fffafrf")
print(func1,func1.__doc__,res)

装饰器模板

from functools import wraps
def outter(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        """此处可定义装饰器的功能"""
        res=func(*args,**kwargs)
        return res
    return wrapper

装饰器(有参装饰器)

给函数传值的方式有两种:一种是函数参数直接传值,另一种是将参数包给被传值函数
**args,**kwargs已经用作给函数体传值(需要根据原函数定义的格式相同);
f用于为函数名传值,因为要用到语法糖,outter()只能传递固定的参数

如果函数体内还需要变量如何传参? 答:再包一层

#挑选不同的认证功能,认证通过则打印消息,否则报错
def decoration(way):  
    def outter(func):
        def wrapper(*args,**kwargs):
            name=input("请输入您的用户名:").strip()
            passwd=input("请输入您的密码:").strip()
            if way=="txt":
                print("文本来源认证方式")
            elif way == "mysql":
                print("数据库来源认证")
            elif  way == "ldap":
                print("ldap认证方式")

            if name=="lzz" and passwd=="123456":
                print("登陆成功")
                res=func(*args,**kwargs)
                return res
            else:
                print("登陆失败")
        return wrapper
    return outter
    
@decoration("mysql")  #会先转换为@outter;可以给内部传递多个参数
def fun1(x,y):
    print("%s 您好,您的账户余额为 %s" %(x,y))
   
@decoration("ldap")
def home(home):
    print("homename is %s" %home)

fun1("lzz",100)
home("袁山")

多个装饰器加载和运行的顺序

def outter1(func1):
    def wrapper1(*args,**kwargs):
        print("装饰器1")
        res=func1(*args,**kwargs)
        return res
    return wrapper1

def outter2(func2):
    def wrapper2(*args,**kwargs):
        print("装饰器2")
        res=func2(*args,**kwargs)
        return res
    return wrapper2

def outter3(func3):
    def wrapper3(*args,**kwargs):
        print("装饰器3")
        res=func3(*args,**kwargs)
        return res
    return wrapper3

@outter1 #wrapper2=outter1(wrapper2)  wrapper2=wrapper1--->func1=wrapper2
@outter2 #wrapper3=outter2(wrappers3)  wrappers=wrapper2--->func2=wrapper3
@outter3 #add=outter3(add)  add=wrapper3 --->func3=add
def add(x,y):
    print(x+y)
add(1,2)

结论: 如果一个函数上有多个语法糖,语法糖的加载顺序是自下而上,执行顺序是自上而下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据工匠大壮

请狠狠粗暴的爱我!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值