闭包函数与装饰器

global与nonlocal

'''global'''
money = 666

def index():
    	global money
        money = 100
        
index()
print(money)
"""
局部名称空间直接修改全局名称空间中的数据
"""
'''nonlocal'''
def index():
    name = 'moon'
    def inner():
        nonlocal name
        name = 'tony'
    inner()
    print(name)
"""
内层局部名称空间修改外层局部名称空间中的数据
"""

函数名的多种用法

函数名其实绑定的也是一块内存地址 只不过该地址里面存放的不是数据值而是一段代码 函数名加括号就会找到该代码并执行
 1.可以当做变量名赋值
 def index():pass
 res = index
 res()
 print(res)

 2.可以当做函数的参数
 def index():
     print('from index')
 def func(a):
     print(a)
     a()
 func(index)

 3.可以当作函数的返回值
 def index():
     print('from index')

 def func():
     print('from func')
     return index
 res = func()
 print(res)
 res()

# def index():
#     print('from index')
#     def func():
#         print('from func')
#     return func
#
# res = index()
# print(res)
# res()

# 4.可以当做容器类型(可以存放多个数据的数据类型)的数据
 def register():
     print('注册功能')

 def login():
     print('登陆功能')

 def withdraw():
     print('提现功能')

 def transfer():
     print('转账功能')

 def shopping():
     print('购物功能')

# 定义功能编号与功能的对应关系
 func_dict = {
     '1':register,
     '2':login,
     '3':withdraw,
     '4':transfer,
     '5':shopping
 }

 while True:
     print("""
     1.注册功能
     2.登陆功能
     3.提现功能
     5.购物功能
     """)
     choice = input('请输入功能的编号:').strip()
     if choice in func_dict:
         func_dict.get(choice)()
     else:
         print('没有此功能')

闭包函数

"""
定义在函数内部的函数 并且用到了外部函数名称空间中的名字
	1.定义在函数内容
	2.用到外部函数名称空间中的名字
"""
def index():
    name = 'moon'
    def inner():
        print(name)
#满足定义在函数内部 但并不满足用到外部函数名称空间中的名字


闭包函数实际应用>>>:是另外一种给函数体代码传参的方式!!!
# 给函数体代码传参的方式1:代码里缺什么变量名就补什么变量名
def register(name,age):
    print(f"""
        姓名:{name}
        年龄:{age}
    """)
register('moon',18)

# 给函数体代码传参的方式2:闭包函数
def outer(name,age):
    def register():
        print(f"""
            姓名:{name}
            年龄:{age}
        """)
    return register
res = outer('moon',18)
res()
res = outer('tony',23)
res()

装饰器简介

1.概念
	在不改变被装饰对象原代码和调用方式的情况下给被装饰对象添加新的功能
2.本质
	并不是一门新技术 而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的结果
3.口诀
	对修改封闭 对扩展开放
4.储备知识
	时间相关操作
    import time
    # print(time.time()) # 时间戳(距离1970-01-01 00:00:00所经历的秒数)
 	time.sleep(3)
    print('早上起来 拥抱太阳')
    
    count = 0
  # 循环前先获取时间戳
	start_time = time.time()
    while count < 100:
        print('开心')
        count +=1
   	end_time = time.time()
    print('循环消耗时间:', end_time - start_time)
    

装饰器推导流程

import time

def index():
    time.sleep(3)
    print('from index')

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

'''1.直接在调用index函数的前后添写代码'''
# start_time = time.time()
# index()
# end_time = time.time()
# print('函数index的执行时间为;',end_time - start_time)

'''2.index调用的地方较多 代码不可能反复拷贝>>>:相同代码需要在不用的地方反复执行>>>:函数'''
# def get_time():
#     start_time = time.time()
#     index()
#     end_time = time.time()
#     print('函数index的执行时间为>>>:',end_time - start_time)
# get_time()

'''3.函数体代码写死了 只能统计index的执行的时间 如何才能做到统计更多的函数运行时间 直接传参变换统计的函数'''
# def get_time(xxx):
#     start_time = time.time()
#     xxx()
#     end_time = time.time()
#     print('函数的执行时间为>>>:',end_time - start_time)
# get_time(index)
# get_time(home)

'''4.虽然实现了一定的兼容性 但不符合装饰器的特征 第一种传参不写 只能考虑闭包'''
# def outer(xxx):
#     def get_time():
#         start_time = time.time()
#         xxx()
#         end_time = time.time()
#         print('函数的执行时间为>>>:',end_time - start_time)
#     return  get_time
# res = outer(index)
# res()
# res = outer(home)
# res()

'''5.调用方式还是不对 如何变形>>>:变量名赋值绑定(*********)马上有内味了'''
# def outer(xxx):
#     def get_time():
#         start_time = time.time()
#         xxx()
#         end_time = time.time()
#         print('函数的执行时间为>>>:',end_time - start_time)
#     return  get_time
# res = outer(index) # 赋值符号左边是一个变量名 可以随意命名
# res1 = outer(index)
# moon = outer(index)
# index = outer(index)
# index()
# home = outer(home)
# home()

'''6.上面的装饰器只能装饰无参函数 兼容性太差'''

# def func(a):
#     time.sleep(0.1)
#     print('from func', a)

# def func1(a, b):
#     time.sleep(0.2)
#     print('from func1', a, b)

# def func2():
#     time.sleep(0.3)
#     print('from func2')

# func(123)

# def outer(xxx):
#     def get_time():
#         start_time = time.time()
#         xxx()
#         end_time = time.time()
#         print('函数的执行时间为:', end_time - start_time)
#     return get_time

# func = outer(func)
# func(1)

# func1 = outer(func1)
# func1(1, 2)

# func2 = outer(func2)
# func2()


'''7.被装饰的函数不知道有没有参数以及几个参数 如何兼容'''
# def func(a):
#     time.sleep(0.1)
#     print('from func',a)
# def func1(a,b):
#     time.sleep(0.2)
#     print('from func1',a, b)
#
# def outer(xxx):
#     def get_time(*args,**kwargs):
#         start_time = time.time()
#         xxx(*args,**kwargs)
#         end_time = time.time()
#         print('函数的执行时间为:', end_time - start_time)
#     return get_time
#
# func = outer(func)
# func(123)
# func1 = outer(func1)
# func1(1,2)

'''如果被装饰的函数有返回值'''


# def func(a):
#     time.sleep(0.5)
#     print('from func', a)
#     return 'func'
#
# def func1(a, b):
#     time.sleep(0.2)
#     print('from func1', a, b)
#     return 'func1'
#
# def outer(xxx):
#     def get_time(*args, **kwargs):
#         start_time = time.time()
#         res = xxx(*args, **kwargs)
#         end_time = time.time()
#         print('函数的执行时间为>>>:', end_time - start_time)
#         return res
#     return get_time
#
# func1 = outer(func1)
# res = func1(123, 123)
# print(res)

装饰器模板

# 务必掌握 
def outer(func):
    def inner(*args, **kwargs):
        # 执行被装饰对象之前可以做的额外操作
        res = func(*args, **kwargs)
        # 执行被装饰对象之后可以做的额外操作
        return res
    return inner

装饰器语法糖

def outer(func_name):
    def inner(*args, **kwargs):
        print('执行被装饰对象之前可以做的额外操作')
        res = func_name(*args, **kwargs)
        print('执行被装饰对象之后可以做的额外操作')
        return res
    return inner
"""
语法糖会自动将下面紧挨着的函数名当做第一个参数自动传给@函数调用
"""
@outer  # func = outer(func)
def func():
    print('from func')
    return 'func'

@outer  # index = outer(index)
def index():
    print('from index')
    return 'index'

func()
index()

作业

1.编写一个用户认证装饰器
  函数:register login transfer withdraw 
  基本要求
   	 执行每个函数的时候必须先校验身份 eg: jason 123
  拔高练习(有点难度)
   	 执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
  提示:全局变量 记录当前用户是否认证

# 定义一个变量记录用户的登录状态
is_login = False


def login_auth(func_name):
    def inner(*args, **kwargs):
        global is_login
        # 先判断全局名称空间中的变量名is_login绑定的值是否为True
        if is_login:
            res = func_name(*args, **kwargs)
            return res
        username = input('username>>>:').strip()
        password = input('password>>>:').strip()
        if username == 'jason' and password == '123':
            # 将全局名称空间中记录用户登录状态的数据值该为True
            is_login = True
            res = func_name(*args, **kwargs)
            return res
        else:
            print('用户名或密码错误无法执行函数')
    return inner


@login_auth
def register():
    print('注册功能')


@login_auth
def login():
    print('登录功能')


@login_auth
def shopping():
    print('购物功能')


register()
login()
shopping()
posted @ 2022-10-11 22:40  Super小赵  阅读(18)  评论(0编辑  收藏  举报
****************************************** 页脚Html代码 ******************************************