函数(三)
global与nonlocal
1.global的用法
1.当不使用global时
number = 89
def index():
number = 34
index()
print(number) # 89
2.使用了global
number = 89
def index():
global number
number = 34
index()
print(number) # 34
"""
局部名称空间直接修改全局名称空间中的数据
"""
2.nonlocal的用法
1.当不使用nonlocal时
def index():
name = 'kiki'
def inner():
name = 'kimi'
inner()
print(name) # kiki
index()
2.当使用了nonlocal
def index():
name = 'kiki'
def inner():
nonlocal name
name = 'kimi'
inner()
print(name) # kimi
index()
"""
内层局部名称空间修改外层局部名称空间中的数据
"""
函数名的多种用法
函数名其实绑定的也是一块内存地址,只不过该地址里面存在的不是数据值,而是一段代码,函数名加括号就会找到代码并执行。函数对象指的是可以被当作‘数据’来处理,具体可分为四个方面的使用
1.可以当作变量名赋值
def index():
pass
res = index
res() # res() == index()
print(res) # <function index at 0x00000213D09461F0>
2.可以当做函数的参数
def index():
print('今天是10月11号')
def func(a):
print(a) # a=index <function index at 0x000002CCA40E61F0>
a() # a()==index() 直接调用index() 输出 ‘今天是10月11号’
func(index)
3.可以当作函数的返回值
1.返回值返回第一个函数名
def index():
print('天气晴')
def func():
print('适合出门')
return index
res = func() # 第一步看赋值的右边,调用func()函数输出‘适合出门’,返回index函数名给res
print(res) # 打印出index的函数名的内存地址 <function index at 0x0000028E8C7361F0>
res() # res() == index() 直接调用index()函数,输出‘天气晴’
2.返回值返回第二个函数名
def index():
print('天气晴')
def func():
print('适合出门')
return func
res = index() # 第一步看赋值的右边,调用index()函数输出‘天气晴’,然后到return返回func
print(res) # 打印出func的函数名内存地址 <function index.<locals>.func at 0x000002876A56A4C0>
res() # res() == func() 直接调用func()函数,输出‘适合出门’
4.可以当作容器类型(可以存放多个数据的数据类型)的数据
1.第一种方式----基础版
def register():
print('注册功能')
def login():
print('登录功能')
def withdraw():
print('提现功能')
def transfer():
print('转账功能')
def shopping():
print('购物功能')
while True:
print("""
1.注册功能
2.登录功能
3.提现功能
4.转账功能
5.购物功能
""")
choice = input('please input your choice>>>:').strip()
if choice == '1':
register()
elif choice == '2':
login()
elif choice == '3':
withdraw()
elif choice == '4':
transfer()
elif choice == '5':
shopping()
else:
print('查无编号!!!!')
2.第二种方式-----升级版
def register():
print('注册功能')
def login():
print('登录功能')
def withdraw():
print('提现功能')
def transfer():
print('转账功能')
def shopping():
print('购物功能')
demo_dict = {
'1':register,
'2':login,
'3':withdraw,
'4':transfer,
'5':shopping
}
while True:
print("""
1.注册功能
2.登录功能
3.提现功能
4.转账功能
5.购物功能
""")
choice = input('please input your choice>>>:').strip()
if choice in demo_dict:
# demo_dict.get(choice)()
name = demo_dict.get(choice)
name()
else:
print('查无编号')
闭包函数
定义在函数内部的函数,并且用到了外部函数名称空间中的名字
1.定义在函数内部
2.用到外部函数名称空间中的名字
def demo():
name = 'kiki'
def inner():
print(name)
""" 第二个函数里name用到了第一个函数name,称为闭包函数 """
闭包函数实际应用:是另外一种给函数体代码传参的方式
方式1:给函数体代码传参(代码里面缺什么变量名形参里面就补什么变量名)
def stu_class(name,age):
print(f"""
姓名:{name}
年龄:{age}
""")
stu_class('kimi',18)
""" 这种方式,输入一次参数就打印出的结果只有一个"""
方式2:闭包函数
def stu_class(name,age):
# name = 'kiki'
# age = 18
def register():
print(f"""
姓名:{name}
年龄:{age}
""")
return register
res = stu_class('kiki',18)
res()
res()
res = stu_class('kimi',20)
res()
res()
""" 这种可以连续输出好几个信息"""
对比信息图如下
解析步骤如下:
对比信息图如下
装饰器
引入
软件的设计应该遵循开放封闭原则,即是对扩展是开放的,而对修改时封闭的,软件包含的所有功能的源代码以及调用方式,都应该避免修改,否则一旦改错,则极有可能产生连锁反应,最终导致程序崩溃。对于新上线的软件,我们可能要对客户的新需求或者变化,对程序提供扩展的可能性,这就用到了装饰器
装饰器简介
1.概念
在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能
2.本质
并不是一门新的技术,而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的结果
3.口诀
对修改封闭、对扩展开放
4.储备知识
时间相关操作
import time
# print(time,time()) # 时间戳(距离1970-01-01 00:00:00所经历的秒数)
time.sleep(2)
print('五点就到饭点了')
count = 0
# 循环之前先获取时间戳
start_time = time.time()
while count<1000:
print('赏心悦目')
count += 10
end_time = time.time()
print('循环消耗的时间:',end_time - start_time)
5.应用场景
用于有切面需求的场景,比如插入日志、性能测试、事务处理、缓存、权限校验等应用场景
装饰器推导过程
import time
def func():
time.sleep(3)
print('花花')
def home():
time.sleep(1)
print('润玥')
""" 1.直接在调用func函数的前后添加代码 """
start_time = time.time()
func() # 花花
end_time = time.time()
print('函数func的执行时间为>>:',end_time - start_time) # 函数func的执行时间为>>: 3.01410174369812
""" 2.func调用的地方较多,代码不可能反复拷贝>>>>:相同的代码需要在不同的位置反复执行>>>:函数"""
def get_time():
start_time = time.time()
func()
end_time = time.time()
print('函数func的执行时间为>>:', end_time - start_time) # 函数func的执行时间为>>: 3.0112600326538086
get_time()
""" 3.函数体代码写死了,只能统计func()的执行时间,如何才能做到统计更多的函数运行时间,直接传参变换统计的函数"""
def get_time(xxx):
start_time = time.time()
xxx()
end_time = time.time()
print('函数func的执行时间为>>:', end_time - start_time)
get_time(func)
get_time(home)
"""4.虽然实现了一定的兼容性,但是并不符合装饰器的特征,第一种转参不写,只能考虑闭包"""
def get_time(xxx):
# xxx = index
def outer():
start_time = time.time()
xxx()
end_time = time.time()
print('函数func的执行时间为>>:', end_time - start_time)
return outer
res = get_time(func)
res()
res1 = get_time(home)
res1()
""" 5.调用方式还是不对,如何变形>>>:变量名赋值绑定(***********)"""
def outer(xxx):
def get_time():
start_time = time.time()
xxx()
end_time = time.time()
return get_time
res = outer(func) # 赋值符号的左边是一个变量名,可以随意命名
res1 =outer(func)
kiki = outer(func)
func =outer(func)
home = outer(home)
home()
"""6.上述装饰器只能装饰无参函数,兼容性太差"""
def func1(a):
time.sleep(1)
print('艾玖', a)
def func2(a, b):
time.sleep(2)
print('福宝', a, b)
def func3():
time.sleep(3)
print('和叶')
func1(123) # 艾玖 123
def outer(xxx):
def get_time(a, b):
start_time = time.time()
xxx(a, b)
end_time = time.time()
print('函数func的执行时间为>>:', end_time - start_time)
return get_time
func2 = outer(func2)
func2(120,119) # 福宝 120 119
func1 = outer(func1)
func1(120) # 艾玖 123
func3 = outer(func3)
func3() # get_time() missing 2 required positional arguments: 'a' and 'b'
"""7.被装饰的函数不知道有没有参数以及几个参数,如何兼容"""
def func1(a):
time.sleep(1)
print('艾玖', a)
def func2(a, b):
time.sleep(2)
print('福宝', 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
func1 = outer(func1)
func1(120) # 艾玖 120
func2 = outer(func2)
func2(120,119) # 福宝 120 119
"""8.如果被装饰的函数有返回值"""
def func1(a):
time.sleep(1)
print('艾玖', a)
return 'func1'
def func2(a, b):
time.sleep(2)
print('福宝', a, b)
return 'func2'
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(120) # 艾玖 120
print(res) # func1
func2 = outer(func2)
res = func2(119, 120) # 福宝 119 120
print(res) # func2
解读步骤如图
装饰器模板
重点掌握:
def outer(func):
def inner(*args,**kwargs):
print('执行被装饰对象之前可以做的额外操作')
res = func(*args,**kwargs)
print('执行被装饰对象之后可以做的额外的操作')
return res
return inner
装饰器语法糖
"""装饰器语法糖,语法糖会自动将下面紧挨着的函数当作第一个参数自动传给@函数调用"""
def outer(func):
def inner(*args,**kwargs):
print('执行被装饰对象之前可以做的额外操作')
res = func(*args,**kwargs)
print('执行被装饰对象之后可以做的额外的操作')
return res
return inner
@outer
def func():
print('和叶')
return 'func'
@outer
def func1():
print('和花')
return 'func1'
func()
func1()
作业
- 编写一个用户认证装饰器
函数:register login transfer withdraw
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123
拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
提示:全局变量 记录当前用户是否认证