内部函数 闭包和装饰器的基础
思想:内部函数主要是为了实现闭包,而装饰器又是基于闭包
内部函数-闭包-装饰器是一个连贯的知识点
函数里面又声明的函数,声明的函数就是内部函数
特点
1.可以访问外部函数的变量
2.内部函数可以修改外部函数的可变类型的变量(如:list1)
3.内部函数修改全局的不可变变量时,需要在内部函数声明: global 变量名
内部函数修改外部函数不可变变量是,需要在内部函数中声明:nonlocal 变量名
def func():
n=100 #局部变量
list1 = [9,20,3,4]
#声明内部函数
def inner_function():
nonlocal n
#对list1里面的元素进行加n操作
for index,i in enumerate(list1):
list1[index]=i+n
#内部函数可以访问局部变量
list1.sort()
n+=1
#函数单纯定义没有任何意义,需要调用一下内部函数
inner_function()
print(list1)
print('打印老大n',n)
func()
'''
打印老大n 101
'''
用debug调试,func()处设置断点
a=100 #全局变量
def func():
b=100 #局部变量
def inner_func():
c=88
#尝试打印a,b,c,的值
print(a,b,c)
inner_func()
func()
'''
100 100 88
'''
a=100 #全局变量
def func():
b=100 #局部变量
def inner_func():
global a
nonlocal b
c=88
#尝试修改
c+=12
b+=12
a+=10
#尝试打印a,b,c,的值
print(a,b,c)
#调用内部函数
inner_func()
print(locals())
func()
'''
110 112 100
{'inner_func': <function func.<locals>.inner_func at 0x000002373BC9A310>, 'b': 112}
'''
locals() 查看当前函数中声明的内容有哪些,以字典形式输出
globals()查看全局变量有哪些,以字典形式输出,里面有一些系统的键值对
闭包
在函数中提出的概念
条件
1.外部函数中定义了内部函数
2.外部函数有返回值
3.返回的值是内部函数(不能加括号,加括号表示调用)
4.内部函数引用了外部函数变量的值
格式
'''
def 外部函数():
...
def 内部函数():
...
return 内部函数
'''
例子
#外部访问内部函数
def func():
a=100
def inner_func():
b=99
print(a,b)
return inner_func #内部函数通过return扔出
x=func()
print(x)
#x就是内部函数,x()表示调用函数
x()
'''
<function func.<locals>.inner_func at 0x00000184D1A1A310>
100 99
'''
def func(a,b):
c=10
def inner_func():
s=a+b+c
print('结果:',s)
return inner_func
#调用func
ifunc=func(6,9) #ifunc就是inner_func
#调用返出来的内部函数
ifunc()
'''
结果: 25
'''
——————分割线——————
装饰器 依赖闭包 闭包的基础上多一个条件:函数作为外层函数的参数
应用场景:加入购物车、付款、修改地址……都要判断用户的登录状态,依赖装饰器
引入
def func(num):
a=100
def inner_func():
nonlocal a #修改局外变量
nonlocal num #传进来的参数num也可以修改
num+=1
for i in range(num):
a+=1
print('修改后a的值:',a)
return inner_func #此处千万不要带括号
#调用func
f = func(5) #func返回的是内部函数
f() #f变为inner_func,()进行调用
'''
修改后a的值: 105
'''
地址引用
def test(): #声明函数
print('---test---')
t=test #函数test赋值给t
#类比
a=10 #声明整型变量
b=a #a值赋给b
test()
t() #即调用test
'''
---test---
---test---
'''
def func(x):
print('--->',x)
a=10
func(a)
'''
---> 10
'''
def test(): #声明函数
print('---test---')
t=test
def func(f):
print(f)
f() #0x00000199AB91F040 去这个地方调用f
func(test) #f=test,同t
'''
<function test at 0x00000199AB91F040>
---test---
'''
整体上只有两个函数和一个调用
特点
1.函数A作为参数出现,函数B接收函数A作为参数
2.要有闭包的特点
#定义一个装饰器
def decorator(func):
a=100
def wrapper(): #包装
func()
print('--->111')
print('--->222',a)
return wrapper
#使用装饰器
@decorator
#不改变原函数名字的情况下,对函数进行装饰
#开发中已经定义好了一个函数,但后来发现函数定义的有问题,想再丰富一下函数
#想再装饰一下
#函数ABC都要调用D,后来AB调用D发现不满足条件,要求D改动,而C对D要求不变
#不改变原名进行装饰
def house():
print('我是毛坯房')
house()
'''
我是毛坯房
--->111
--->222 100
'''
decorator做了啥
def decorator(func):
a=100
print('wrapper外层打印测试')
def wrapper(): #包装
func()
print('--->111')
print('--->222',a)
print('wrapper加载完成...')
return wrapper
@decorator
def house(): #被装饰函数
print('我是毛坯房')
print(house)
'''
wrapper外层打印测试
wrapper加载完成...
<function decorator.<locals>.wrapper at 0x000001B71917A3A0>
'''
1.house被装饰函数
2.将被装饰函数作为参数传给装饰器decorator
3.执行decorator函数(底层完成执行)
4.将返回值又赋值给house