函数名的用法,闭包函数与装饰器
函数的多种用法与装饰器
global与nonlocal
1. global用在局部名称空间直接修改全局名称空间中的数据
x = 111
def func():
global x # 修改全局名称空间x值
x = 222
func()
print(x) # 222
------------------------------------------------------------------------------------
2. nonlocal 内层局部名称空间修改外层局部名称空间数据
def func():
x = 222
def func1():
nonlocal x # 修改外部名称空间x值
x = 444
func1()
print(x) # 444
func()
函数名的多种用法
什么是函数名
函数名其实就是绑定的一块内存空间,只不过内存空间里是一串代码,我们在调用函数名的时候就会执行该名绑定的代码
多种用法
1. 可以当做变量名赋值
def func():
print('变量名赋值用法')
res = func # 变量名res 也绑定func的内存地址 (一段代码)
print(res) # 打印res 结果是function func 已经指向函数func
res() # res就等于函数func 调用res() = 调用函数func()
执行func函数体代码,打印 '变量名赋值用法'
------------------------------------------------------------------------------------
2.可以当做函数的参数
def func(): # 1 定义函数func
print('from func') # 6 打印
def func1(a): # 2 定义函数func1
print(a) # 4 此时a指向函数func 的内存地址(func的代码)
a() # 5 调用b变量名a() = 调用函数 func()
func1(func) # 3 调用函数func1并传函数func 与a绑定
----------------------------------------------------------------------------------
3.可以当做函数的返回值
def func(): # 1 定义函数func
print('哈哈哈') # 9 打印哈哈哈
def func1(): # 2 定义函数func1
print('嘿嘿嘿') # 4 打印嘿嘿嘿
return func # 5 返回函数func 给func 1
res = func1() # 3 有赋值符号先看右边,调用函数func1 # 6 res接收函数func返回值
print(res) # 7 打印res绑定的内存地址 function func
res() # 8 调用res() = 调用函数func()
----------------------------------------------------------------------------------
4.可以当做容器使用
def register(): # 定义函数
print('注册功能')
def login(): # 定义函数
print('登录功能')
def check_all(): # 定义函数
print('查找功能')
def revamp(): # 定义函数
print('修改功能')
def remove(): # 定义函数
print('删除功能')
# 创建一个字典,用编号对应函数功能
func_dict = {
'1': register,
'2': login,
'3': check_all,
'4': revamp,
'5': remove
}
# 循环功能
while True:
# 打印功能供用户选择
print("""
1.注册功能
2.登录功能
3.查找功能
4.修改功能
5,删除功能
""")
# 获取用户选择
choice = input('请输入想要执行的功能编号').strip()
# 判断用户输入的编号是否在字典里
if choice in func_dict:
# 在的情况下,执行num 绑定字典中该编号的函数并调用
num = func_dict.get(choice)()
else:
# 不在的情况打印没有此功能
print('功能不存在')
闭包函数
闭包函数要领
定义在函数内部的函数,并且用到了外部函数名称空间的名字。
代码:
def f1(): # 1 定义函数f1
x = '我在外部' # 3 x = 我在外部
def f2(): # 4 定义函数 f 2
print(x) # 6 打印变量名x 我在外部
f2() # 5 调用函数f2
f1() # 2 调用函数f1
-----------------------------------------------------------------------------------
用法1:另外一种给函数体代码传参的方式
def f1(name, home): # 1 定义函数 f1 设置形参 name home
print(f"""
姓名:{name}
住址:{home}
""") # 3 格式化打印 引用name home 数据值
f1('tank', 'china') # 2 调用函数f1 传 实参给 形参按位置绑定
-----------------------------------------------------------------------------------
用法2:闭包函数
def f1(name, home): # 1 定义函数f1 设置形参 name home
def f2(): # 3 f2函数
print(f"""
姓名:{name}
国籍:{home}
""") # 7 打印
return f2 # 4 返回函数 f2 给 f1
res = f1('jack', 'usa') # 2 先看右侧 调用f1并给给函数传参
# 5 f1 返回值 f2 与 res 绑定
res() # 6 调用f2
res = f1('tony', 'england') # 修改实参 同上
res()
装饰器
装饰器简介
装饰器概念:
在不改变被装饰对象原代码和原调用方式的情况下,给被装饰对象增加新功能。
本质:
其实就是结合了函数参数,名称空间,函数多种用法,闭包函数组合到一起的结果
"""
对修改封闭,对扩展开发
"""
------------------------------------------------------------------------------------
储备知识,时间相关操作
import time
time.sleep(3)
print('时间太长了 厕所该堵了')
循环用法:
count = 1 # 计时器
# 循环之前获取时间戳, 时间戳:1970年 00:00:00 距离现在过了多少秒
star_time = time.time()
while count < 100000: # 计数器小于10000次时
count += 1 # 计数器+1
end_time = time.time() # 获取结束时间
print('本次上厕所消耗时间', end_time-star_time)
装饰器推导流程
需求计算index函数运行时间
'''直接在index前后添加时间代码'''
import time
star_time = time.time()
def index():
time.sleep(2) # 停下两秒
print('from index')
def home():
time.sleep(3) # 停下3 秒
print('form home')
index()
end_time = time.time()
print('此次消耗', end_time - star_time) # 两秒
'''我们可能在很多地方调用index不可能每调用一次就要写一次'''
------------------------------------------------------------------------------------
''' 这里我们就能联想到 函数的意义:相同的代码在不同的地方反复执行'''
'''使用函数方法,如果函数产生多个形参的话,并不能兼容,而且和装饰器不符合,调用方法不符'''
def get_time(xxx): # 1定义函数
stat_time = time.time() # 3 获取时间戳
xxx() # 4 调用xxx() 此时xxx和函数index绑定等于调用 index()
# 5 回到函数index里执行函数体代码
end_time = time.time() # 6 获取结束时间
print('耗时', end_time - stat_time) # 7 结束时间-开始时间 = 耗时
get_time(index) # 2 给函数传参 变量名xxx 指向 函数index 内存空间
get_time(home) # 同上
-----------------------------------------------------------------------------------
'''使用 闭包函数方法'''
def outer(xxx): # 1定义函数outer 设置形参
def get_time(): # 3定义函数
stat_time = time.time() # 7获取时间戳
xxx() # 8此时xxx绑定函数index 回去执行函数index的代码
end_time = time.time() # 9 获取结束时间
print('耗时', end_time - stat_time) # 10 打印
return get_time # 4 get_time返回值给 res
res = outer(index) # 2先看右边xxx 绑定index # 5 res接收返回值函数get_time
res() # 6 调用res此时res= get_time
res1 = outer(home) # 同上
res1()
'''此时我们看这段代码还是和装饰器不符,调用方式被改变 '''
------------------------------------------------------------------------------------
'''直接用使用和函数名一样的变量名'''
def outer(xxx): # 1定义函数outer 设置形参
def get_time(): # 3定义函数
stat_time = time.time() # 7获取时间戳
xxx() # 8此时xxx绑定函数index 回去执行函数index的代码
end_time = time.time() # 9 获取结束时间
print('耗时', end_time - stat_time) # 10 打印
return get_time # 4 get_time返回值给变量名index
index = outer(index) # 2先看右边xxx 绑定index #5变量名index接收返回值函数get_time
index() # 6 调用index()此时index() = get_time()
home = outer(home)
home()
'''此时虽然调用方法符合装饰器了,但是如果函数有参数呢'''
------------------------------------------------------------------------------------
'''有参数使用方法'''
import time
def index(a, b):
time.sleep(2)
print('from index', a, b)
def home(c, d):
time.sleep(3)
print('form home', c, d)
def outer(xxx): # 定义函数outer设置形参
def get_time(a, b): # 3定义函数 设置形参
stat_time = time.time() # 7获取时间戳
xxx(a, b) """ 8 此时调用xxx绑定函数index 在局部名称空间里查找变量名a,b 此时a=1,b=2 。回去执行函数index的代码 """
end_time = time.time() # 9 获取结束时间
print('耗时', end_time - stat_time) # 10 打印
return get_time # get_time返回值给变量名index
index = outer(index) # 2先看右边xxx 绑定index # 5变量名index接收返回值函数get_time
index(1, 2) # 6 调用index(1, 2)此时index(1,2) = get_time(a,b) a=1 b=2
home = outer(home) # 同上
home(3, 4)
'''此时虽然解决了函数有参数以及有几个参数,但是如果不知道函数有几个参数又或有返回值呢,那么我们就可以使用可变长参数'''
------------------------------------------------------------------------------------
''' 可变长参数使用方法'''
def outer(xxx): # 1定义函数 设置形参xxx
def inner(*args, **kwargs): # 3 定义函数设置形参
stat_time = time.time() # 6 获取时间戳
res = xxx(*args, **kwargs) """ 7 此时调用xxx绑定函数index 在局部名称空间里查找变量名*args 此时*args=(1,2,)可变长实参在传参时会把数据取出传输给函数。回去执行函数index的代码 """
end_time = time.time() # 8获取结束时间
print('此次耗时', end_time - stat_time) # 9打印
return res # 10 返回函数res给res变量名
return inner # 4 函数inner绑定变量名index
index = outer(index) # 2 右边 xxx 指向index 5, index绑定函数inner
res = index(1, 2) """# 6 先看右边调用index(1,2)此时等于函数inner(*args, **kwargs) 形参*args用于接收多余位置参数,结果是元组""" # 11 变量名res接收函数res
print(res) # 空 None
装饰器模板(给我背,滚瓜乱熟)
语法:
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()
作业
a = [False]
def outer(func_name):
def inner(*args, **kwargs):
if a[0]:
res = func_name(*args, **kwargs)
return res
username = input('请输入用户名').strip()
password = input('请输入密码').strip()
if username == 'tank' and password == '123':
print('验证通过')
res = func_name(*args, **kwargs)
a[0] = True
return res
else:
print('验证失败')
return inner
@outer
def register():
print('注册功能')
@outer
def login():
print('登录功能')
@outer
def transfer():
print('转账功能')
@outer
def withdraw():
print('取钱功能')
func_dict = {
'1': register,
'2': login,
'3': transfer,
'4': withdraw,
}
while True:
print("""
1.注册功能
2.登录功能
3.转账功能
4.取钱功能
""")
choice = input('请输入想要执行的功能编号(q)').strip()
if choice == 'q':
break
if choice in func_dict:
num = func_dict.get(choice)()
else:
print('不存在此功能')