闭包函数、装饰器、练习

今日内容详情

闭包函数

闭包函数简介

1.构成闭包函数的特征:
	1.1 是定义在函数内部的函数
    1.2 并且内部使用了外部函数名称空间的名字
	只有符合上述两个特征的函数才能够称之为闭包函数
2.实例
	def func1():
        name = 'nana'
        def func2():
            print(name)  # nana
        return func2
    res = func1()
    res()


    def func1(name):
        # name = 'nana'
        def func2():
            print(name)  # xiao
        return func2
    res1 = func1('xiao')
    res1()

闭包函数的实际应用

给函数体代码传值的方式有两个,一是通过形参传值,而是通过闭包函数传值

1.通过形参传值
	eg:
	def func(name):
        print(name)  # nana
    func('nana')
2.通过闭包函数传值
	eg:
    def func1(name):
        def func2():
            print(name)  # nana
        return func2
    res = func1('nana')
    res()

装饰器

装饰器简介

1.装饰器的本质:在不改变被装饰对象原来的'调用方式'和'内部代码'的情况下给被装饰对象添加新的功能
2.装饰器的原则:对修改封闭,对扩展开放
3.知识储备:
	3.1 时间戳(秒数):指当前距离1970年1月1日0时0分0秒所经历的秒数
	import time 
     print(time.time())  # 1657004718.7669668
     

装饰器前期推导

import time
def index():
    time.sleep(3)
    print('from index')
# 需求:统计函数index运行的时间
1.
    start_time = time.time()
    index()  # from index
    end_time = time.time()
    print("该函数运行的时间是:",end_time-start_time)  # 该函数运行的时间是: 3.010453462600708
 ps:缺陷:如果有多个index需要统计执行时间,这需要 重复编写代码
    解决措施:封装成函数
    
2.封装成函数
	def func():
        start_time = time.time()  # 在调用index函数之前获取一下时间戳
        index()  # from index  调用index函数
        end_time = time.time()
        print("该函数运行的时间是:",end_time-start_time)  # 该函数运行的时间是: 3.0146448612213135
    func()
 ps:缺陷:被调用的函数固定死了,如果有多个不同的函数想要统计执行时间,那么上述的解决措施不够完善
    解决措施:给函数添加形参
    
3.给函数添加形参(方式一)
	def func(xxx):
        start_time = time.time()  
        xxx()  
        end_time = time.time()
        print("该函数运行的时间是:",end_time-start_time)  

    def home():
        time.sleep(5)
        print('from home')

    func(index)  # from index 该函数运行的时间是: 3.0043678283691406
    func(home)  # from home 该函数运行的时间是: 5.01212739944458
 ps:缺陷:当被调用的函数有形参时,上述代码报错
    解决措施:用可变长参数解决
    
4.可变长参数解决
	def func(xxx):
        start_time = time.time()
        xxx(*args,**kwargs)  # 解释器识别不了 报错
        end_time = time.time()
        print("该函数运行的时间是:",end_time-start_time)

    def home(a):
        time.sleep(5)
        print('from home')

    func(index)
    func(home)
 ps:缺陷: 1.*args和**args在目前代码中无法实现
    	  2.改变了原来的调用方式
    解决措施:装饰器推导流程
5. 直接利用形参的形式传参无法实现不改变调用方式,第二种方式尝试用闭包函数
	def outer(xxx):
        def func():
            start_time = time.time()
            xxx()
            end_time = time.time()
            print("该函数运行的时间是:",end_time-start_time)
        return func
    def home():
        time.sleep(5)
        print('from home')

    res = outer(index)
    res()  # from index  该函数运行的时间是: 3.0006649494171143
    print(res)  # <function outer.<locals>.func at 0x00000241241BD158>

    res1 = outer(home)
    res1()  # from home 该函数运行的时间是: 5.002208709716797
    print(res1)  # <function outer.<locals>.func at 0x00000241241BD268>
    # res和res1的名字是变量名,可以取任意的值,那我们用与被调用的函数的函数名,是否可以呢?
    index = outer(index)  # from index 该函数运行的时间是: 3.0072708129882812
    index()
    print(index) # <function outer.<locals>.func at 0x00000248DD6FD158>

    home = outer(home) # from home  该函数运行的时间是: 5.007205009460449
    home()
    print(home) # <function outer.<locals>.func at 0x00000248DD6FD268>
 ps:缺陷:当被调用的函数有形参时,上述代码报错 
    解决措施:用可变长参数解决

装饰 器优化版本

5.用可变长参数解决被张氏对象含参问题
    import time
    def index():
        time.sleep(3)
        print('from index')
        return '执行index返回值'
    def home(a):
        time.sleep(5)
        print('from home')
        return '执行home返回值'
    def outer(xxx):
        def func(*args,**kwargs):  # 此时可变长参数起得的在形参的作用
            start_time = time.time()
            xxx(*args,**kwargs)  # 此时的可变长参数起的是在实参中的作用
            end_time = time.time()
            print("该函数运行的时间是:",end_time-start_time)
        return func

    index = outer(index)  # from index
    index()  # 该函数运行的时间是: 3.0008184909820557
    res1 = index()
    print(res1)  # None

    home = outer(home)
    home(1)  # from home 该函数运行的时间是: 5.003419876098633
    res2 = home(1)
    print(res2)  # None
 ps:缺陷:当被想要获取被装饰对象的返回值时,获取不到
    解决方法:在装饰器内增加一个返回值
    
6.获取被装饰对象的返回值
    import time
    def index():
        time.sleep(3)
        print('from index')
        return '执行index返回值'
    def home(a):
        time.sleep(5)
        print('from home')
        return '执行home返回值'
    def outer(xxx):
        def func(*args,**kwargs):  # 此时可变长参数起得的在形参的作用
            start_time = time.time()
            res = xxx(*args,**kwargs)  # 此时的可变长参数起的是在实参中的作用
            end_time = time.time()
            print("该函数运行的时间是:",end_time-start_time)
            return res
        return func

    index = outer(index)  # from index
    index()  # 该函数运行的时间是: 3.0008184909820557
    res1 = index()
    print(res1)  # 执行index返回值

    home = outer(home)
    home(1)  # from home 该函数运行的时间是: 5.003419876098633
    res2 = home(1) 
    print(res2)  # 执行home返回值

装饰器固定模板

from functools import wraps
def outer(func_name):
    @wraps(func_name)  # 仅仅是为了让装饰器不容易被别人发现 做到真正的以假乱真
    def inner(*args, **kwargs):
        print('执行被装饰对象之前可以做的额外操作')
        res = func_name(*args, **kwargs)
        print('执行被装饰对象之后可以做的额外操作')
        return res
    return inner

装饰器语法糖

语法糖加载被装饰对象函数上面
eg:
    import time
    from functools import wraps

    def outer(func_name):
        @wraps(func_name)
        def func(*args,**kwargs):  # 此时可变长参数起得的在形参的作用
            start_time = time.time()
            res = func_name(*args,**kwargs)  # 此时的可变长参数起的是在实参中的作用
            end_time = time.time()
            print("该函数运行的时间是:",end_time-start_time)
            return res
        return func
    @outer  # index = outer(index)
    def index():
        time.sleep(3)
        print('from index')
        return '执行index返回值'
    @outer  # home = outer(home)
    def home(a):
        time.sleep(5)
        print('from home')
        return '执行home返回值'

    index()  # from index 该函数运行的时间是: 3.002319812774658
    help(index)  # Help on function index in module __main__: index()
    home(1)  # from home  该函数运行的时间是: 5.011131525039673
    help(home)  # Help on function home in module __main__: home(a)

作业

1.编写一个用户认证装饰器
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123

from functools import wraps

def outer(func_name):
    @wraps(func_name)
    def inner(*args,**kwargs):
        if tag_login is True:
            res = func_name(*args,**kwargs)
        else:
            print("没弄上")
        return res
    return inner

dic_info = {}
def register():
    user_name = input("请输入你的用户名>>>:").strip()
    user_pwd = input("请输入你的用户名密码>>>").strip()
    user_money = 100
    dic_info['name'] = user_name
    dic_info['pwd'] = user_pwd
    dic_info['money'] = user_money
    print(f'用户{user_name}注册成功')
def login():
    user_name = input("请输入你的用户名>>>:").strip()
    user_pwd = input("请输入你的用户名密码>>>").strip()
    if user_name == dic_info['name'] and user_pwd == dic_info['pwd']:
        print("登录成功")
        global tag_login
        tag_login = True
    else:
        print("用户名或密码错误")
@outer
def transfer():
        user_trans_money = input("请输入你想要转账的金额>>>:").strip()
        user_trans_money = int(user_trans_money)
        if dic_info['money'] < user_trans_money:
            print('钱不够')
        else:
            dic_info['money'] -= user_trans_money
            print("转账成功")
@outer
def withdraw():
        user_out_money = input("请输入你提款的金额:>>>").strip()
        user_out_money = int(user_out_money)

        if dic_info['money'] < user_out_money:
            print('钱不够')
        else:
            dic_info['money'] -= user_out_money
            print("提款成功")
dict1 = {
    '1':register,
    '2':login,
    '3':transfer,
    '4':withdraw
}
tag_login = False
while True:
    print("""
    ======================
    1.注册功能
    2.登录功能
    3.转账功能
    4.提现功能
    ======================
    """)
    choice = input("请输入你的选择>>.:").strip()
    if choice in dict1:
        dict1.get(choice)()
    else:
        print("请输入正确的指令")

2.拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
函数:register login transfer withdraw
提示:全局变量 记录当前用户是否认证

from functools import wraps


def outer(func_name):
    @wraps(func_name)
    def inner(*args, **kwargs):
        if tag_login is True:
            res = func_name()
            return res
        else:
            print("没弄上")

    return inner


dic_outer = {}


def register():
    user_id = input("请输入的你的用户名编号>>>:").strip()
    if user_id in dic_outer:
        print("该用户名已经存在了")
    else:
        user_name = input("请输入你的用户名>>>:").strip()
        user_pwd = input("请输入你的用户名密码>>>").strip()
        user_money = 100
        dic_info = {}
        dic_info['name'] = user_name
        dic_info['pwd'] = user_pwd
        dic_info['money'] = user_money
        print(f'用户{user_name}注册成功')
        dic_outer[user_id] = dic_info


def login():
    user_id = input("请输入的你的用户名编号>>>:").strip()
    if user_id not in dic_outer:
        print("该用户不存在")
    else:
        user_name = input("请输入你的用户名>>>:").strip()
        user_pwd = input("请输入你的用户名密码>>>").strip()
        if user_name == dic_outer[user_id]['name'] and user_pwd == dic_outer[user_id]['pwd']:
            print("登录成功")
            global tag_login
            tag_login = True
        else:
            print("用户名或密码错误")


@outer
def transfer():
    user_id = input("请输入的你的用户名编号>>>:").strip()
    if user_id not in dic_outer:
        print("该用户不存在")
    else:
        user_trans_id = input("请输入你想转账的用户名编号>>>:").strip()
        if user_trans_id not in dic_outer:
            print("你想转的用户名不在")
        else:
            user_trans_money = input("请输入你想要转账的金额>>>:").strip()
            user_trans_money = int(user_trans_money)
            if dic_outer[user_id]['money'] < user_trans_money:
                print('钱不够')
            else:
                dic_outer[user_id]['money'] -= user_trans_money
                dic_outer[user_trans_id]['money'] += user_trans_money
                print("转账成功")


@outer
def withdraw():
    user_id = input("请输入的你的用户名编号>>>:").strip()
    if user_id not in dic_outer:
        print("该用户名不存在")
    else:
        user_out_money = input("请输入你提款的金额:>>>").strip()
        user_out_money = int(user_out_money)

        if dic_outer[user_id]['money'] < user_out_money:
            print('钱不够')
        else:
            dic_outer[user_id]['money'] -= user_out_money
            print("提款成功")


dict1 = {
    '1': register,
    '2': login,
    '3': transfer,
    '4': withdraw
}
tag_login = False
while True:
    print("""
    ======================
    1.注册功能
    2.登录功能
    3.转账功能
    4.提现功能
    ======================
    """)
    choice = input("请输入你的选择>>.:").strip()
    if choice in dict1:
        dict1.get(choice)()
    else:
        print("请输入正确的指令")
posted @ 2022-07-05 20:28  DRAMA-娜娜  阅读(19)  评论(0编辑  收藏  举报