函数嵌套,闭包,装饰器
名称空间
命名空间:存放名字和值的关系的空间
命名空间分类:
内置命名空间 >>>存放python解释器为我们提供的名字, list, tuple, str, int这些都是内置命名空间
全局命名空间 >>> 我们直接在py文件中, 函数外声明的变量都属于全局命名空间
局部命名空间 >>>在函数中声明的变量会放在局部命名空间
加载顺序:
内置命名空间 >>> 全局命名空间 >>> 局部命名空间
取值顺序:
局部命名空间 >>> 全局命名空间 >>> 内置命名空间
作用域命名空间:
全局作用域:全局命名空间 + 内置命名空间
局部作用域:局部命名空间
内容查看:
globals() >>>查看全局作用域中的内容
locals() >>>查看局部作用域中的变量和函数信息
函数嵌套
函数嵌套只要遇见了函数名+()就是在调用函数
函数顺序:
1
def func_1(): # 1定义func_1 print("1") # 6打印“1” # def func_2(): # 2定义func_2 print ("2") # 4打印“2” func_1() # 5调用func_1 7返回调用者 print("3") # 8打印“3” func_2() # 3调用func_2 9返回func_2调用 print("4") # 10打印“4” #2 #1 #3 #4
2
def func_1(): #1定义函数func_1 print("1") #4打印“1” def func_2(): #5定义func_2 print("2") #8打印“2” print("3") #6打印“3” func_2() #7调用函数func_2 #9返回func_2调用者 print("4") #10打印“4” print("5") #2打印“5” func_1() #3调用func_1 #11返回func_1调用者 print("6") #12打印“6” #5 #1 #3 #2 #4 #6
global、nonlocal
global在函数内部修改全局变量,没有的新声明一个。
a = 100 《global:将变量修改为全局变量》 def func(): global a a = 25 print(f"函数:{a}") #函数:25 func() print(f"内层:{a}") #内层:25
nonlocal 修改上一级变量,没有的继续向上查找,到最外层结束,没有时会报错,不能修改全局的。
a = 100 《nonlocal:修改就近一层变量》 def func1(): a = 25 def func2(): nonlocal a a = 10 print(f"内层:{a}") # 内层:10 func2() print(f"函数:{a}") #函数:10 func1() print(f"内层:{a}") #内层:100
函数名
函数名是一个变量与括号配合可以执行函数
函数名函数的内存地址
def func(): print('1') print(func) #<function func at 0x0000000002071EA0>
函数名可以赋值给其他变量
def func(): print('1') a = func a() #1 打印了“1”,说明函数被调用
函数名可以作为容器类数据类型的元素
def func1(): print("AA") def func2(): print("BB") def func3(): print("CC") lst = [func1, func2, func3] for i in lst: i() #AA #BB #CC
函数名可以当做函数的参数
def func(): print("a") def func1(x): print("b") x() func1(func) # b # a
函数名可以作为函数的返回值
def func1(): 1 print("a1") 3 def func2(): 4 print("b") 9 print("a2") 5 return func2 6 fn = func1() 2 7 fn() 8 10 # a1 # a2 # b
闭包
闭包:内层函数引用外层函数变量()非全局变量)的嵌套函数
def func1() 《闭包》 a = "abc" def func2(): print(a) func2() func1() # 结果: abc
闭包检测
def func1(): 《检测闭包__closure__,是:cell...,否:None》 a = "abc" def func2(): print(a) func2() print(f"func2闭包判断:{func2.__closure__}") func1() print(f"func1闭包判断:{func1.__closure__}") # abc # func2闭包判断:(<cell at 0x0000000001DF6558: str object at 0x0000000001DAB340>,) # func1闭包判断:None
闭包调用
def outer(): 《执行完外部函数返回内部函数名,然后加括号就可调用》 name = "alex" # 内部函数 def inner(): print(name) return inner fn = outer() # 访问外部函数, 获取到内部函数的函数地址 fn() # 访问内部函数
嵌套多层时
def func1(): 《嵌套多层时一层一层往回返》 def func2(): def func3(): print("嘿嘿") return func3 return func2 func1()()()
闭包的优点
保护变量不被外界修改
使变量生命周期延长
节省开辟空间和销毁空间的时间差
装饰器
装饰内容的一个工具
开放封闭原则
对扩展开放
对修改源代码封闭
不改变调用方式
作用
不改变源代码的基础上添加功能
def inner(x): 《装饰器,装饰函数inner(),被装饰函数func()》 def wapeer(): start_time = time.time() #时间戳,记录执行时的时间点 x() end_time = time.time() #时间戳,记录执行时的时间点 print(end_time - start_time) return wapeer import time def func(): time.sleep(2) #暂停2秒 print("睡2秒") func = inner(func) func() # 睡2秒 # 2.0001144409179688
语法糖
被装饰的函数名 = 装饰器的名称(被装饰的函数名)
def inner(x): 《装饰器,装饰函数inner(),被装饰函数func()》 def wapeer(): start_time = time.time() #时间戳,记录执行时的时间点 x() end_time = time.time() #时间戳,记录执行时的时间点 print(end_time - start_time) return wapeer import time
@inner #语法糖
def func(): time.sleep(2) #暂停2秒 print("睡2秒") #省去了'func = inner(func)'是语法糖的原始机制 func() # 睡2秒 # 2.0001144409179688
简单的装饰器
#简单的装饰器模式 def adorner(func): def inner(*args,**kwargs): """被装饰函数调用前""" ret = func() """被装饰函数调用后""" return ret return inner @adorner def foo(x,y): print(x,y) foo(1,1)
functools import wraps 装饰多个函数时,保证被装饰函数的name的值保持不变
from functools import wraps def adorner(func): @wraps(func) #加在最内层函数上方,可以查看函数名、注释等 def inner(*args,**kwargs): """被装饰函数调用前""" ret = func(*args,**kwargs) """被装饰函数调用后""" return ret return inner @adorner def foo(x,y): """ 打印参数值 :param x: :param y: :return: """ print(x,y) foo(1,1) print(f"函数注释{foo.__doc__}") print(f"函数名{foo.__name__}")
带参数的装饰器
def outer(flag): def adorner(func): def inner(*args,**kwargs): if flag: print('''执行函数之前要做的''') re = func(*args,**kwargs) if flag: print('''执行函数之后要做的''') return re return inner return adorner @outer(True) # True时可以执行修饰动作,False时不执行修饰动作 def func(): print(111) func()
多个装饰器修饰一个函数
def adorner_1(func): def inner(*args,**kwargs): print("adorner_1,函数前的") func(*args,**kwargs) print("adorner_1,函数后的") return inner def adorner_2(func): def inner(*args,**kwargs): print("adorner_2,函数前的") func(*args,**kwargs) print("adorner_2,函数后的") return inner @adorner_2 @adorner_1 def f(): print("调用函数f") f() # adorner_2,函数前的 # adorner_1,函数前的 # 调用函数f # adorner_1,函数后的 # adorner_2,函数后的
总结:
装饰器本质是闭包
语法糖单独一行
遵守开放封闭原则,开发对外扩展,封闭修改源代码。
不能修改调用方式
装饰器的应用:
不能说测试函数运行时间
为函数增加一些功能
校验用户登录的时候,Diango,面向对象
函数嵌套和闭包
浙公网安备 33010602011771号