Python-装饰器

一、概念

1、定义一个函数(类),这个函数的功能就是用来装饰其他函数的;(这个函数是用来给其他函数添加额外的功能的);

2、开放封闭原则:

(1)开放:对扩展功能(增加功能)开放。扩展功能的意思是在源代码不做任何改变的情况下,为其增加功能;

(2)封闭:对修改源代码是封闭的;

3、装饰器:不修改被装饰对象的源代码,也不修改调用方式的前提下,给被装饰对象添加新的功能;


插曲:

运用了time.time()=计算现在距unix元年的时间(1970年1月1日8点0分0秒)

二、无参装饰器例子:

# 源代码
def inside(group, s):
    print('欢迎来到王者荣耀')
    print(f'你出身在{group}阵营')
    print(f'敌军还有{s}秒到达战场')
    time.sleep(s)
    print('全军出击')


inside('红色', 5)

运行结果:

欢迎来到王者荣耀
你出身在红色阵营
敌军还有5秒到达战场
全军出击

# 统计上述代码运行时间

方案一:没有修改调用方式,修改了源代码
# 方案一
# 没有修改调用方式,修改了源代码
def inside(group, s):
    start =time.time()
    print('欢迎来到王者荣耀')
    print(f'你出身在{group}阵营')
    print(f'敌军还有{s}秒到达战场')
    time.sleep(s)
    print('全军出击')
    end =time.time()
    print(end-start)


inside('红色', 5)

运行结果:

欢迎来到王者荣耀
你出身在红色阵营
敌军还有5秒到达战场
全军出击
5.010248899459839

方案二:既未修改源代码,又未修改调用方式;但是若该函数调用多次,代码冗余
def inside(group, s):

    print('欢迎来到王者荣耀')
    print(f'你出身在{group}阵营')
    print(f'敌军还有{s}秒到达战场')
    time.sleep(s)
    print('全军出击')


start =time.time()
inside('红色', 5)
end =time.time()
print(end-start)
方案三:解决了方案二的代码冗余问题,没有修改源代码,同时增加新功能,但被装饰对象的调用方式被修改
def inside(group, s):

    print('欢迎来到王者荣耀')
    print(f'你出身在{group}阵营')
    print(f'敌军还有{s}秒到达战场')
    time.sleep(s)
    print('全军出击')


def wrapper(): # wrapper;装饰器,装饰品
    start = time.time()
    inside('红色', 5)
    end = time.time()
    print(end - start)

wrapper()
方案四:解决方案三的问题,解决了传参数量的问题,但是只针对inside函数
def inside(group, s):
    print('欢迎来到王者荣耀')
    print(f'你出身在{group}阵营')
    print(f'敌军还有{s}秒到达战场')
    time.sleep(s)
    print('全军出击')


def wrapper(*args, **kwargs):  # 无论给wrapper函数传多少个参数,均可成功传参
    start = time.time()
    inside(*args, **kwargs)
    end = time.time()
    print(end - start)


wrapper()
方案五:
def inside(group, s):
    print('欢迎来到王者荣耀')
    print(f'你出身在{group}阵营')
    print(f'敌军还有{s}秒到达战场')
    time.sleep(s)
    print('全军出击')


# 通过闭包的方式传参

def outer(func):
    # func =inside # 将函数的内存地址作为参数传,例如这里只能是inside
    def wrapper(*args, **kwargs):  # 无论给wrapper函数传多少个参数,均可成功传参
        start = time.time()
        func(*args, **kwargs)
        end = time.time()
        print(end - start)
    return wrapper  # 这里加(),就是直接调用wrapper,得到的是wrapper的返回值;
    # 不加(),得到的是wrapper的内存地址,全局就可以访问wrapper

# wrapper的内存地址就是outer的返回值,也就是res
res = outer(inside)   # 通过传参的方式,res也可换成inside

# 调用wrapper,给wrapper传参=给装饰对象传参
res('蓝色',3)

补充:

(1)

def charge (num):
    for i in range(num,101):
        time.sleep(0.05)
        print(f'当前电量:{i}%')
    print('电量已充满')

charge(1)

运行结果:

(2)

 /r :回车,调到当前行的开头

print 默认在最后带一个换行符,通过end=‘ ’,来处理

def charge(num):
    for i in range(num, 101):
        time.sleep(0.05)
        print(f'\r当前电量:{i}%', end='')
    print('电量已充满')

charge(2)

# 运行结果

(3)

def charge(num):
    for i in range(num, 101):
        time.sleep(0.05)
        # 制作进度条,字符串可以做乘法计算,一个字符串X10 就是10个字符串
        print(f'\r当前电量:{"◇"*i} {i}%', end='') # 外面用单引号,里边不可用单引号
    print('电量已充满')

charge(2)

运行结果;


三、无参装饰器有返回值,例子-2,装饰对象有返回值

def charge(num):
    for i in range(num, 101):
        time.sleep(0.05)
        # 制作进度条,字符串可以做乘法计算,一个字符串X10 就是10个字符串
        print(f'\r当前电量:{"◇" * i} {i}%', end='')  # 外面用单引号,里边不可用单引号
    print('电量已充满')
    return 100


# charge(2)

def outer(func):
    # func =inside # 将函数的内存地址作为参数传,例如这里只能是inside
    def wrapper(*args, **kwargs):  # 无论给wrapper函数传多少个参数,均可成功传参
        start = time.time()
        response = func(*args, **kwargs)  # response 接返回值
        end = time.time()
        print(end - start)
        return response

    return wrapper  # 这里加(),就是直接调用wrapper,得到的是wrapper的返回值;
    # 不加(),得到的是wrapper的内存地址,全局就可以访问wrapper


# wrapper的内存地址就是outer的返回值,也就是res
charge = outer(charge)  # 通过传参的方式,res也可换成inside
print(charge)
charge(10)

四、语法糖-代码更简洁

@装饰器函数

def outer(func):
    # func =inside # 将函数的内存地址作为参数传,例如这里只能是inside
    def wrapper(*args, **kwargs):  # 无论给wrapper函数传多少个参数,均可成功传参
        start = time.time()
        response = func(*args, **kwargs)  # response 接返回值
        end = time.time()
        print(end - start)
        return response

    return wrapper  # 这里加(),就是直接调用wrapper,得到的是wrapper的返回值;
    # 不加(),得到的是wrapper的内存地址,全局就可以访问wrapper

@outer  # 只要运行到这行代码,就相当于执行 charge= outer(charge)
def charge(num):
    for i in range(num, 101):
        time.sleep(0.05)
        # 制作进度条,字符串可以做乘法计算,一个字符串X10 就是10个字符串
        print(f'\r当前电量:{"◇" * i} {i}%', end='')  # 外面用单引号,里边不可用单引号
    print('电量已充满')
    return 100

五、无参装饰器模版

def outer(func):
    def wrapper(*args, **kwargs):  # 装饰器
        response = func(*args, **kwargs)  # 调用原函数
        return response

    return wrapper  # 返回wrapper内存地址,调用wrapper


@outer
def func():  # 原函数
    pass

1、点击pycharm的file,再点击settings,再settings界面点击ELive Templates;

2、按下图操作

3、效果图,按回车键,就自动生成装饰器模版代码

六、有参装饰器

print(home,--name--)   # home 是一个函数,--name--是读函数名字的属性

#运用闭包函数

def g_outer(x, y):
    def outer(func):
        def wrapper(*args, **kwargs):
            response = func(*args, **kwargs)
            print(x, y)
            return response
        return wrapper
    return outer

@g_outer('x','y')
def resource():
    print('这是源代码')

resource()

七、有参装饰器实际应用

def g_outer(source):
    def outer(func):
        def wapper(*args, **kwargs):
            name = input("请输入账号》》》")
            password = input("请输入密码》》》")
            if source == 'file':
                print("基于文件的登录验证")
                if name == 'jack' and password == '123':
                    res = func(*args, **kwargs)
                    return res
                else:
                    print('账号或密码错误!')

            elif source == 'sql':
                print("基于sql的登录验证")
            elif source == 'ldap':
                print("基于ldap的登录验证")
            else:
                print('不支持此类登录验证')

        return wapper

    return outer


@g_outer('file')
def home():
    print('welcome')


@g_outer('sql')
def index():
    pass


@g_outer('ldap')
def defalut():
    pass


home()
index()
defalut()

运行结果:

请输入账号》》》jack
请输入密码》》》12
基于文件的登录验证
账号或密码错误!
请输入账号》》》jack
请输入密码》》》123
基于sql的登录验证
请输入账号》》》jack
请输入密码》》》123
基于ldap的登录验证

八、装饰器叠加

类似于堆栈

def outer1(func):
    def wapper(*args, **kwargs):
        print('执行outer1')
        res = func(*args, **kwargs)  # 这个的func是原home的内存地址
        print('outer1 执行完毕')
        return res

    return wapper


def outer2(func):
    def wapper(*args, **kwargs):
        print('执行outer2')
        res = func(*args, **kwargs)  # 这里的func = outer1.wrapper
        print('outer2 执行完毕')
        return res

    return wapper


def outer3(func):
    def wapper(*args, **kwargs):
        print('执行outer3')
        res = func(*args, **kwargs)  # 这里的func = outer2.wrapper
        print('outer3 执行完毕')
        return res

    return wapper


# 装饰器的叠加
# 装饰器的执行顺序是outer1,2,3
@outer3  # home3 =outer3(home2)
@outer2  # home2 =outer2(home1)
@outer1  # home1 =outer1(home)  home1 ,outer1.wrapper
def home(z):
    print('执行home功能', z)
    return 'zx'


res = home(0)
print(res)

运行结果:

执行outer3
执行outer2
执行outer1
执行home功能 0
outer1 执行完毕
outer2 执行完毕
outer3 执行完毕

zx

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值