- global和nonlocal用法
- 函数名的多种用法
- 闭包函数
- 装饰器介绍
- 装饰器推导流程(原理)
- 装饰器模板
- 装饰器语法糖
- 多层语法糖
- 有参装饰器
- 装饰器模板
- 装饰器修复技术
- 递归函数
- 练习题及答案
1.global与nonlocal用法
1.
global 主要是用在局部名称空间,它可以在局部名称空间直接修改全局名称空间的数据
2.
nonlocal 主要是用在局部名称空间,它可以在局部名称空间直接修改外部(上一层)局部名称空间的数据
例1:
name = 55
def func():
global name
name = 11
func()
print(name)
例2:
def func():
name = 11
def subd():
nonlocal name
name = 22
subd()
print(name)
func()
2.函数名的多种用法
函数名绑定的也是一块内存地址,只不过内存地址存放的不是数据值而是函数下面的函数体代码
我们打印函数名(不加括号)他会出现:
我们加上括号就可以调用此函数名对应的函数体代码
因此函数名的多种用法使用如下:
1.函数名可以作为参数
def func1():pass
def func(func1):
print(func1)
func(func1)
2.函数名可以赋值给变量名
def func():
print('i am real man')
data = func()
print(data)
3.函数名可以当作函数的返回值
例1:
def func1():
print('真棒')
def func():
print('你好')
return(func1)
data = func()
data()
print(data)
例2:
def func():
print('hello world')
return func
def func1():
print('hello girl')
data = func()
print(data)
data()
4.可以作为容器数据类型里面的数据值(可以存放多个数据的数据类型)
def register():
print('注册功能')
def login():
print('注册功能')
def shopping():
print('购物功能')
def check_account():
print('查看账户功能')
def quit():
print('退出功能')
choice_data = {
'1':register,
'2':login,
'3':shopping,
'4':check_account,
'5':quit
}
while True:
print(
'1.注册功能\n'
'2.登录功能\n'
'3.购物功能\n'
'4.查看账户功能\n'
'5.退出功能\n'
)
user_choice = input('请输入您想要执行的功能编号>>>>>:')
if user_choice in choice_data:
choice_data.get(user_choice)()
else:
print('请选择已存在功能的编号')
3.闭包函数
1.闭包的定义
'''
定义在函数内部的函数,并且用到了外部函数名称空间中的名字
1.定义在函数内部的函数
2.用到外部函数名称空间中的名字
'''
def func():
name = 'xiaoming'
def func1():
print(name)
func1()
func()
2.闭包函数的实际应用
是另外一种给函数体代码传参的方法
def func(name,password):
print(f'姓名:{name}\n密码:{password}')
func('小明',123)
函数需要什么参数我们传什么参数即可
但是这种方法不方便修改,我们每次使用函数都需要在里面填值
def outer(name,password):
def inner():
print(f'姓名:{name}\n密码:{password}')
return inner
data = outer('小明',1234)
data()
这样我们只要调用data() 那么就会把
姓名:小明
密码:1234
结果呈现出来,需要的时候只要重新写
data = outer(name,password)
然后继续调用data()即可。
4.装饰器介绍
1.装饰器的概念
2.装饰器的本质
3.口诀
4.装饰器前戏(储备知识)
调用模块
import time
time.sleep(2)
print('就是牛蛙')
有一个需求是计时一下这个代码从运行到结束 过去了多少时间:
import time
count = 0
start_time = time.time()
while count < 100:
print('牛蛙')
count += 1
end_time = time.time()
print(f'从运行开始到结束一共过去了', end_time - start_time)
我们就可以这样实现此功能
5.装饰器原理推导过程
我们在前面装饰器前戏部分已经提到了需求,我们现在需要通过函数来实现它
import time
def func():
time.sleep(2)
print('你好,牛蛙')
def func1():
time.sleep(1)
print('好的哥')
我们想要计算它开始运行到结束所需的时间
我们可以:
import time
def func():
time.sleep(2)
print('你好,牛蛙')
def func1():
time.sleep(1)
print('好的哥')
start_time = time.time() 开始时间
func()
end_time = time.time()
print(f'从运行开始到结束一共过去了', end_time - start_time)
import time
def func():
time.sleep(2)
print('你好,牛蛙')
def get_time():
start_time = time.time()
func()
end_time = time.time()
print(f'从运行开始到结束一共过去了', end_time - start_time)
get_time()
import time
def func():
time.sleep(2)
print('你好,牛蛙')
def func1():
time.sleep(1)
print('好的哥')
def get_time(function):
strat_time = time.time()
function()
end_time = time.time()
print(f'从运行开始到结束一共过去了', end_time - start_time)
get_time(func)
get_time(func1)
结果:
你好,牛蛙
从运行开始到结束一共过去了 2.01809024810791
好的哥
从运行开始到结束一共过去了 1.0098073482513428
我们接下来来满足一下它的要求:
import time
def func():
time.sleep(2)
print('你好,牛蛙')
def func1():
time.sleep(1)
print('好的哥')
def outer(function):
def inner():
strat_time = time.time()
function()
end_time = time.time()
print(f'从运行开始到结束一共过去了', end_time - start_time)
return inner
data = outer(func)
data()
dtaa = outer(func1)
data()
接下来,我们一起来看看 data 我们能不能改成func 函数名呢?
import time
def func():
time.sleep(2)
print('你好,牛蛙')
def func1():
time.sleep(1)
print('好的哥')
def outer(function):
def inner():
strat_time = time.time()
function()
end_time = time.time()
print(f'从运行开始到结束一共过去了', end_time - start_time)
return inner
func = outer(func)
func()
func1 = outer(func1)
func1()
上述装饰器只能装饰无参函数,兼容性不好,我们在看看如何装饰有参函数
import time
def func(a):
time.sleep(2)
print('你好,牛蛙',a)
def func1(a,b):
time.sleep(1)
print('好的哥',a,b)
def outer(function):
def inner(a,b):
strat_time = time.time()
function(a,b)
end_time = time.time()
print(f'从运行开始到结束一共过去了', end_time - start_time)
return inner
func1 = outer(func1)
func1(1,2)
那么我们可以看一下以下操作,
import time
def func(a):
time.sleep(2)
print('你好,牛蛙',a)
def func1(a,b)
time.sleep(1)
print('好的哥',a,b)
def func2():
time.sleep(1.5)
print('明白了')
def outer(function):
def inner(*args,**kwargs):
start_time = time.time()
function(*args,**kwargs)
end_time = time.time()
print('函数的执行时间为>:',end_time - start_time)
return inner
func = outer(func)
func(1)
func1 = outer(func1)
func1(2,3)
func2 = outer(func2)
func2()
我们来看一下被装饰函数有返回值的情况
import time
def func(a):
time.sleep(2)
print('你好,牛蛙',a)
return 666
def func1(a,b):
time.sleep(1)
print('好的哥',a,b)
return 777
def func2():
time.sleep(1.5)
print('明白了')
return 888
def outer(function):
def inner(*args,**kwargs):
start_time = time.time()
b = function(*args,**kwargs)
end_time = time.time()
print('函数的执行时间为>:',end_time - start_time)
return b
return inner
func = outer(func)
b = func(1)
print(b)
func1 = outer(func1)
b = func1(1,2)
print(b)
func2 = outer(func2)
b = func2()
print(b)
有返回值的时候我们需要在 inner函数内给返回值赋值一个变量名,并且 return 这个返回值
这样我们打印这个变量名就可以获取到它的返回值
到此我们的装饰器也就算圆满完成任务。
6.装饰器模板
def outer(function):
def inner(*args,**kwargs):
res = function(*args,**kwargs)
return res
return innner
7.装饰器语法糖
def outer(func_name):
def inner(*args, **kwargs):
print('执行被装饰对象之前可以做的额外操作')
res = func_name(*args, **kwargs)
print('执行被装饰对象之后可以做的额外操作')
return res
return inner
"""
语法糖会自动将下面紧挨着的函数名当做第一个参数自动传给@函数调用
"""
@outer
def func():
print('from func')
return 'func'
@outer
def index():
print('from index')
return 'index'
func()
index()
8.多层语法糖
"""
多层语法糖 加载顺序由下往上
每次执行之后如果上面还有语法糖 则直接将返回值函数名传给上面的语法糖
如果上面没有语法糖了 则变形 index = outter1(wrapper2)
"""
在我们正常使用语法糖的时候一般是@装饰器
这样的一个操作
我们先来看一下一层语法糖
我们先写一个装饰器
def outer(function):
def inner(*args,**kwargs):
res = function(*args,**kwargs)
return res
return inner
@outer
def func():
print('我是Func')
func()
例子1:多层语法糖
def outter1(func1):
print('加载了outter1')
def wrapper1(*args, **kwargs):
print('执行了wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outter2(func2):
print('加载了outter2')
def wrapper2(*args, **kwargs):
print('执行了wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def outter3(func3):
print('加载了outter3')
def wrapper3(*args, **kwargs):
print('执行了wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
@outter1
@outter2
@outter3
def index():
print('from index')
index()
9.有参装饰器
def outer(mode):
def login_auth(func_name):
def inner(*args,**kwargs)
username = input('username>>>>:').strip()
password = input('password>>>>:').strip()
if mode == '1':
print('使用模式1')
elif mode == '2':
print('使用模式2')
elif mode == '3':
print('使用模式3')
res = func_name(*args,**kwargs)
return res
return inner
return login_auth
'''
当装饰器中需要额外的参数时,我们需要在给装饰器增加一层传参
在函数名加括号是执行优先级最高的
我们应该先看函数名加括号的执行
在看语法糖的操作
'''
def index():
print('from index')
index()
def func():
print('from func')
func()
10.装饰器模板
无参装饰器模板(常用)
def outer(function):
def inner(*args,**kwargs):
res = function(*args,**kwargs)
return res
return inner
有参装饰器模板(不太用)
def outer_plus(x):
def outer(function):
def inner(*args,**kwargs)
res = function(*args,**kwargs)
return res
return inner
return outer
@outer_plus('33')
def func():
print('你好')
func()
11.装饰器修复技术
在介绍修复技术之前介绍一个函数方法:
help()
它可以帮助我们查看一些函数的具体注释内容
我们知道被装饰器装饰的函数其实已经不是它自己本身了,如果我们想要help()它,它显示的是装饰器部分的内容
所以我们如果想要让help()函数显示它自己本身的内容的话我们可以在
装饰器开头加上
from functools import wraps
def outer(func_name):
@wraps(func_name)
def inner(*args,**kwargs):
res = func_name(*args,**kwargs)
return res
return inner
12.递归函数
函数的递归调用
函数直接或者间接调用了函数自身
例子:
直接调用
def index():
print('from index')
index()
index()
我们执行这个index() 但是会一直重复在这个函数里面,这样我们的函数内部名称空间就在不断的增加存储量
我们的Python解释器它会在一定次数后停止这个递归,是为了保护计算机放置爆掉内存
间接调用:
def index():
print('123')
func()
def func()
print('456')
index()
func()
这两个函数互相调用自己本身,也跟直接调用一样,如果python解释器没有干预的话我们的内存会被它们产生的信息填满
也就是我们最多是能执行1000次,我们的python解释器会自动帮我们停止操作
递归函数:
1.直接或间接调用自己(函数)
2.每次调用都必须比上一次简单,并且有一个需要明确的结束条件
递推:一层层往下
回溯:基于明确的结果一层层往上
"""
get_age(5) = get_age(4) + 2
get_age(4) = get_age(3) + 2
get_age(3) = get_age(2) + 2
get_age(2) = get_age(1) + 2
get_age(1) = 18
"""
def get_age(n):
if n == 1:
return 18
return get_age(n-1) + 2
res = get_age(5)
print(res)
13.练习题及答案
1.利用递归函数依次打印列表中每一个数据值
l1 = [1,[2,[3,[4,[5,[6,[7,[8,]]]]]]]]
2.利用有参装饰器编写多种用户登录校验策略
login_dict = {'uesr':None}
def outer_plus(mode):
def outer(func):
def inner(*args,**kwargs):
if login_dict.get('user'):
if mode == '1':
print('模式1')
res = func(*args, **kwargs)
return res
elif mode == '2':
print('模式2')
res = func(*args, **kwargs)
return res
elif mode == '3':
print('模式3')
res = func(*args, **kwargs)
return res
elif mode == '4':
print('模式4')
res = func(*args, **kwargs)
return res
else:
username = input('请输入用户名>>>>>:')
password = input('请输入密码>>>>>:')
if username == 'jason' and password == '123':
login_dict['user'] = True
if mode == '1':
print('模式1')
res = func(*args, **kwargs)
return res
elif mode == '2':
print('模式2')
res = func(*args, **kwargs)
return res
elif mode == '3':
print('模式3')
res = func(*args, **kwargs)
return res
elif mode == '4':
print('模式4')
res = func(*args, **kwargs)
return res
else:
print('用户名或密码错误!')
return inner
return outer
@outer_plus('1')
def register():
print('注册功能')
@outer_plus('2')
def login():
print('登录功能')
@outer_plus('3')
def transfer():
print('转账功能')
@outer_plus('4')
def withdraw():
print('提现功能')
choice_dict = {'2': register,
'1': login,
'3': transfer,
'4': withdraw
}
while True:
print('1.登录\n'
'2.注册\n'
'3.转账\n'
'4.提现\n'
)
choice = input('请输入您想要执行的功能>>>>:')
if choice in choice_dict:
choice_dict.get(choice)()
elif choice.lower() == 'q':
print('程序结束')
break
else:
print('请重新输入功能编号')
尽量搞懂装饰器推导流程
编写一个用户认证装饰器
函数:register login transfer withdraw
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123
拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
提示:全局变量 记录当前用户是否认证