函数与装饰器

今日内容总结

global与nonlocal

money = 666


def index():
    global money
    money = 123


index()
print(money)  # 123
"""
global局部名称空间直接修改全局名称空间中的数据
"""
def index():
    name = 'qyf'

    def inner():
        nonlocal name
        name = 'wei'

    inner()
    print(name)


index()  # wei
"""
nonlocal内层局部名称空间修改外层局部名称空间中的数据
"""

函数名的多种用法

函数名绑定的也就是一块内存地址 只不过该地址里面存放的不是数据值而是一段代码 函数名加括号就会找到该代码并执行
1.可以当作变量名赋值
def index(): pass
res = index  # 将index的内存地址赋值给变量名res
res()  # res()等于调用index函数下的函数体代码
2.可以当做函数的参数
def index():
    print('from index')
def func(a):  # 将index内存地址赋值给a
    print(a)  # 打印a也就是打印index的内存地址
    a()  # 等于调用index函数 运行index下函数体代码
func(index)  # 调用func函数传参数index
3.可以当作函数的返回值
def index():
    print('from index')
def func():
    print('from func')
    return index
res = func()  # 调用func函数 执行打印并将index的内存地址返回并赋值给res
print(res)  # 打印index内存地址
res()  # 等于调用index函数体代码
def index():
    print('from index')
    def func():
        print('from func')
    return func
res = index()  # 先调用index函数 执行打印并将返回的func内存地址赋值给res
print(res)  # 打印func内存地址
res()  # 等于调用func函数体代码
4.可以当做容器类型(可以存放多个数据的数据类型)的数据
def register():
    print('注册功能')
def login():
    print('登录功能')
def withdraw():
    print('提现功能')
def transfer():
    print('转账功能')
def shopping():
    print('购物功能')
# 定义功能编号与功能的对应关系
fun_dict = {
    '1': register,
    '2': login,
    '3': withdraw,
    '4': transfer,
    '5': shopping
}
while True:
    print("""
    1.注册功能
    2.登录功能
    3.提现功能
    4.转账功能
    5.购物功能
    """)
    choice = input('输入编号>>>:').strip()
    if choice in fun_dict:
        fun_name = fun_dict.get(choice)
        fun_name()
    else:
        print('没有此功能编号')

闭包函数

"""
定义在函数内部的函数 并且用到了外部函数名称空间中的名字
1.定义在函数内的内容
2.用到外部函数名称空间中的名字
"""
def index()
	name = 'qyf'
	def inner():
		print(name)
闭包函数实际应用>>>:是另外一种给函数体代码传参的方式
给函数体代码传参的方式1:代码里面缺什么变量名 
                 形参里面就补什么变量名
def register(name, age):
    print(f"""
    姓名:{name}
    年龄:{age}
    """)
register('qyf', 23)
给函数体代码传参的方式2:闭包函数
def outer(name, age):
    def register():
        print(f"""
        姓名:{name}
        年龄:{age}
        """)
    return register
res = outer('qyf', 23)
res()
res = outer('wei', 23)
res()

装饰器

装饰器简介

1.概念
在不改变被装饰对象原代码和调用方式的情况下给被装饰对象添加新的功能
2.本质
并不是一门新的技术 而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的结果
3.口诀
对修改封闭 对拓展开放
4.储备知识
时间相关操作
import time
print(time.time())  # # 时间戳(距离1970-01-01 00:00:00所经历的秒数)
time.sleep(3)  # 3秒后执行后面的代码
print('666')

count = 0
# 循环之前先获取时间戳
start_time = time.time()
while count < 5000:
    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(func):
    start_time = time.time()
    func()
    end_time = time.time()
    print('函数的执行时间为>>>:', end_time - start_time)
get_time(index)
get_time(home)
"""4.虽然实现了一定的兼容性 但是并不符合装饰器的特征 第一种传参不合适 只能考虑闭包函数"""
def outer(func):
    def get_time():
        start_time = time.time()
        func()
        end_time = time.time()
        print('函数的执行时间为>>>:', end_time - start_time)
    return get_time
res = outer(index)
res()
res1 = outer(home)
res1()
"""5.调用方式还是改变了 并不满足装饰器特征
    如何变形>>>:变量名赋值绑定(***********)"""
def outer(func):
    def get_time():
        start_time = time.time()
        func()
        end_time = time.time()
        print('函数的执行时间为>>>:', end_time - start_time)
    return get_time
index = outer(index)  # 赋值符号的左边是一个变量名可以随意命名
home = outer(home)
index()
home()
"""6.上述装饰器只能装饰无参函数 兼容性太差"""
import time
def index(a):
    time.sleep(3)
    print('from index', a)
def home(a, b):
    time.sleep(1)
    print('from home', a, b)
def outer(func):
    def get_time(a, b):
        start_time = time.time()
        func(a, b)
        end_time = time.time()
        print('函数的执行时间为>>>:', end_time - start_time)
    return get_time
index = outer(index)
home = outer(home)
# index(1)  # 报错
home(1, 2)
"""7.被装饰的函数不知道有没有参数以及有几个参数
    如何兼容"""
import time
def index(a):
    time.sleep(3)
    print('from index', a)
def home(a, b):
    time.sleep(1)
    print('from home', a, b)
def short():
    time.sleep(2)
    print('from short')
def outer(func):
    def get_time(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print('函数的执行时间为>>>:', end_time - start_time)
    return get_time
index = outer(index)
home = outer(home)
short = outer(short)
index(1)
home(1, 2)
short()
"""8.如果被装饰的函数有返回值"""
import time
def index(a):
    time.sleep(3)
    print('from index', a)
    return 'index'
def home(a, b):
    time.sleep(1)
    print('from home', a, b)
    return 'home'
def short():
    time.sleep(2)
    print('from short')
    return 'short'
def outer(func):
    def get_time(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)
        end_time = time.time()
        print('函数的执行时间为>>>:', end_time - start_time)
        return res
    return get_time
index = outer(index)
home = outer(home)
short = outer(short)
res = index(1)
print(res)
res = home(1, 2)
print(res)
res = short()
print(res)

装饰器模板

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

装饰器语法糖

def outer(func_num):
    def inner(*args, **kwargs):
        print('执行被装饰对象之前要做的额外操作')
        res = func_num(*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
  拔高练习(有点难度)
   	 执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
  提示:全局变量 记录当前用户是否认证
user_state = False
def outer(func):
    def inner(*args, **kwargs):
        global user_state
        if user_state:
            res = func(*args, **kwargs)
            return res
        name = input('name>>>:').strip()
        pwd = input('pwd>>>:').strip()
        if name == 'qyf' and pwd == '123':
            print('登陆成功')
            user_state = True
            res = func(*args, **kwargs)
            return res
        else:
            print('账户或密码错误')
    return inner


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


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


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


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


fun_dict = {
    '1': register,
    '2': login,
    '3': withdraw,
    '4': transfer,
}

while True:
    print("""
        1.注册功能
        2.登录功能
        3.提现功能
        4.转账功能
        """)
    choice = input('输入编号>>>:').strip()
    if choice in fun_dict:
        res = fun_dict.get(choice)
        res()
    else:
        print('没有此功能编号')
posted @ 2022-10-11 17:31  小白峰  阅读(31)  评论(0)    收藏  举报