python之装饰器

1、装饰器
1.1、什么是装饰器
器指的是工具/功能
装饰指的是为被装饰对象添加额外的功能
大白话:定义装饰器就是定义了一个函数,该函数就是用来为其他函数添加额外的功能的
1.2、为何要用装饰器
程序的开发需要遵循一个原则:开放封闭原则
开放:指的是对拓展功能开放
封闭:指的是对修改源代码封闭

总结:装饰器就是在不修改被装饰对象源代码以及调用方式的前提为被装饰对象添加上新功能
1.3、如何使用装饰器
1.3.1、模拟统计程序的运行时间
import time

def index(x, y):
    time.sleep(3)
    print('index===>', x, y)
# index(1,2)

def home(name):
    time.sleep(2)
    print('home====>', name)
# home("allen")

def outter():
    x = index

    def wrapper(a, b):
        start_time = time.time()
        x(a, b) # 为index函数传参
        stop_time = time.time()
        print("run time is :%s" % (stop_time - start_time)) # 模拟统计程序的运行时间
    return wrapper  # 千万不要加括号

index = outter()  # f=wrapper
index(1, 2)  # wrapper()
1.3.2、装饰器的改进1
import time

def index(x, y):
    time.sleep(3)
    print('index===>', x, y)

def home(name):
    time.sleep(2)
    print('home====>', name)

def outter(x):
    # x = home
    def wrapper(*args,**kargs):
        start_time = time.time()
        x(*args,**kargs) # x("allen")
        stop_time = time.time()
        print("run time is :%s" % (stop_time - start_time))
    return wrapper  # 千万不要加括号

index = outter(index)  # index=wrapper
home = outter(home)  # home=wrapper


index(1, 2)  # wrapper(1,2)
home("allen")  # wrapper("allen")
1.3.3、装饰器的改进2
import time

def index(x, y):
    time.sleep(3)
    print('index===>', x, y)
    return 456

def home(name):
    time.sleep(2)
    print('home====>', name)
    return 123


def outter(x):
    # x = home
    def wrapper(*args, **kargs):
        start_time = time.time()
        res = x(*args, **kargs)  # x("allen")
        stop_time = time.time()
        print("run time is :%s" % (stop_time - start_time))
        return res
    return wrapper  # 千万不要加括号

index = outter(index)  # index=wrapper
home = outter(home)  # home=wrapper

res1 = index(1, 2)  # wrapper(1,2)
res2 = home("allen")  # wrapper("allen")
print("====>",res1)
print("====>",res2)
1.4、语法糖
# 使用语法糖改写上面的程序:
import time

def outter(x):
    # x = home
    def wrapper(*args, **kargs):
        start_time = time.time()
        res = x(*args, **kargs)  # x("allen")
        stop_time = time.time()
        print("run time is :%s" % (stop_time - start_time))
        return res
    return wrapper  # 千万不要加括号

@outter  # index = outter(index)  # index=wrapper
def index(x, y):
    time.sleep(3)
    print('index===>', x, y)
    return 456

@outter  # home = outter(home)  # home=wrapper
def home(name):
    time.sleep(2)
    print('home====>', name)
    return 123


res1 = index(1, 2)  # wrapper(1,2)
res2 = home("allen")  # wrapper("allen")
print("====>", res1)
print("====>", res2)
1.5、wraps的使用
from functools import wraps

def timmer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start=time.time()
        res = func(*args, **kwargs)
        stop=time.time()
        print(stop - start)
        return res
    # wrapper.__name__ = func.__name__
    # wrapper.__doc__ = func.__doc__
    return wrapper

@timmer # index=timmer(index) # index=wrapper
def index(x, y):
    """
    这是index函数的文档注释
    """
    time.sleep(1)
    print('index===>', x, y)
    return 456

# index(1,2)
# print(index.__name__)
help(index)
1.6、完整的装饰器模板总结
from functools import wraps

def outter(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        return res
    return wrapper
1.7、叠加多个装饰器的加载、运行分析
def deco1(func1):  # func1 = wrapper2的内存地址
    def wrapper1(*args, **kwargs):
        print('正在运行===>deco1.wrapper1')
        res1 = func1(*args, **kwargs)
        return res1
    return wrapper1

def deco2(func2):  # func2 = wrapper3的内存地址
    def wrapper2(*args, **kwargs):
        print('正在运行===>deco2.wrapper2')
        res2 = func2(*args, **kwargs)
        return res2
    return wrapper2

def deco3(x):
    def outter3(func3):  # func3=被装饰对象index函数的内存地址
        def wrapper3(*args, **kwargs):
            print('正在运行===>deco3.outter3.wrapper3')
            res3 = func3(*args, **kwargs)
            return res3
        return wrapper3
    return outter3

# 加载顺序自下而上(了解)
@deco1  # index=deco1(wrapper2的内存地址)        ===> index=wrapper1的内存地址
@deco2  # index=deco2(wrapper3的内存地址)        ===> index=wrapper2的内存地址
@deco3(111)  # ===>@outter3===> index=outter3(index) ===> index=wrapper3的内存地址
def index(x, y):
    print('from index %s:%s' % (x, y))

# 执行顺序自上而下的,即wraper1 -> wrapper2 -> wrapper3
index(1, 2)  # wrapper1(1,2)

结论:
1、装饰器的加载顺序是自下而上的
2、装饰器的执行顺序是自上而下的
2、有参装饰器
2.1、定义与使用
由于语法糖@的限制,outter函数只能有一个参数,并且该参数只用来接收被装饰对象的内存地址
def outter(func):
    # func = 函数的内存地址
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        return res
    return wrapper

# @outter # index=outter(index) # index=>wrapper
@outter # outter(index)
def index(x,y):
    print(x,y)

引出两点:
1、可以通过闭包的方式为函数体传参,可以包一层,也可以包两层
2、@后跟的必须是一个函数的内存地址
   @函数的内存地址(1,2) 是可以的,但是前提是调用函数"函数的内存地址(1,2)"的
   返回值必须是一个函数的内存地址
2.2、有参装饰器的应用
def outter2(mode):
    def outter(func):
        def wrapper(*args, **kwargs):
            inp_name=input("please input your name: ").strip()
            inp_pwd=input("please input your password: ").strip()
            if mode == "file":
                print('认证来源=====>file')
                with open('user.db', mode='rt', encoding='utf-8') as f:
                    for line in f:
                        name_db,pwd_db=line.strip('\n').split(':')
                        if inp_name == name_db and inp_pwd == pwd_db:
                            print('login successful')
                            res = func(*args, **kwargs)
                            return res
                    else:
                        print("账号或密码错误")
            elif mode == "ldap":
                print('认证来源=====>ldap')
            elif mode == "mysql":
                print('认证来源=====>mysql')
            else:
                print("未知的认证来源")
        return wrapper
    return outter

@outter2(mode="mysql") # index=outter(index) ==>index=wrapper
def index(x, y):
    print('index===>', x, y)

index(1, 2) # wrapper(1,2)
2.3、有参装饰器模板总结
# 有参装饰器模板
def 有参装饰器(x,y,z):
    def outter(func):
        def wrapper(*args, **kwargs):
            res = func(*args, **kwargs)
            return res
        return wrapper
    return outter

@有参装饰器(1,y=2,z=3)
def 被装饰对象():
    pass
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值