我的Python之旅第四天
一 名称空间、作用域、取值顺序
1 名称空间
当程序运行时,代码从上至下依次执行,它会将变量与值得关系存储在一个空间中,这个空间就叫做名称空间,也叫命名空间、全局名称空间。
当程序遇到函数时,他会将函数名存在内存中,对函数体漠不关心。
当函数执行时,内存会临时开辟一个空间,存放函数体里面的代码(变量,代码等),函数外面访问不到临时空间的内容,随着函数的执行完毕,临时名称空间会释放掉,这个临时开辟的空间就叫名称空间,也叫局部名称空间。
Python中名称空间分三种:
- 内置名称空间
- 全局名称空间
- 局部名称空间
2 作用域
-
全局作用域
内置名称空间
全局名称空间
-
局部作用域
局部名称空间
3 加载顺序
内置名称空间à全局名称空间(当程序执行时)à局部名称空间(当函数调用时)
4 取值顺序:单向不可逆
局部名称空间(当函数调用时)à全局名称空间(当程序执行时)à内置名称空间
二 内置函数globals、locals
1返回值
(1)globals()
返回一个字典,字典里面的内容是全局作用域的内容。
(2) locals
返回一个字典,当前位置 的所有变量。
2 示例
name='ShiPotian' age='1000' sex='f' def func1(): name2='XieYanke' age=100 print('全局作用域为:',globals()) print('局部作用域为:',locals()) func1() 结果为: 全局作用域为: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000176723DC198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Python/python周末班/day04/globals,locals.py', '__cached__': None, 'name': 'ShiPotian', 'age': '1000', 'sex': 'f', 'func1': <function func1 at 0x0000017672033E18>} 局部作用域为: {'age': 100, 'name2': 'XieYanke'}
name='ShiPotian' age='18' sex='f' def func2(): name2='白自在' age=10000 def func3(): name3='石中玉' age3='19' print('全局作用域为:',globals()) print('局部作用域为:',locals()) func3() func2() 结果为: 全局作用域为: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000297D51CC198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Python/python周末班/day04/globals,locals.py', '__cached__': None, 'name': 'ShiPotian', 'age': '18', 'sex': 'f', 'func2': <function func2 at 0x00000297D4E23E18>} 局部作用域为: {'age3': '19', 'name3': '石中玉'}
三 global与nonlocal
1 global
(1)引用并改变一个全局变量
count=1 def func1(): global count count= count+1 count=count+100 print(count) func1() 结果为:102
(2)在局部作用域声明一个全局变量
def func2(): global name name='谢烟客' print('局部定义的全局变量:',name) func2() print('全局引用局部定义的全局变量:',name) 结果为: 局部定义的全局变量: 谢烟客 全局引用局部定义的全局变量: 谢烟客
2 nonlocal
(1)不能操作全局变量,从那层引用的变量,就从那层开始全部改变
count = 100 def func3(): count = 1 def inner1(): nonlocal count count = count + 3 print('开始引用层的变量值:',count) def inner2(): pass inner1() print('第一层函数的变量值:',count func3() print("全局作用域的变量值:",count) 结果为: 开始引用层的变量值: 4 第一层函数的变量值: 4 全局作用域的变量值: 100
(2)取值
引用而不是改变,想要改变上层空间的变量,要用到global、nonlocal
3 特别注意
(1)对于可变的数据类型 list dict set 不用global nonlocal
(2)如果默认参数是一个可变的数据类型,那么他在内存中永远是一个
示例
def extendList(val,list=[]): list.append(val) return list list1 = extendList(10) list2 = extendList(123,[]) list3 = extendList('a') print('list1=%s'%list1) print('list2=%s'%list2) print('list3=%s'%list3) 结果为: list1=[10, 'a'] list2=[123] list3=[10, 'a']
四 函数名的应用
1 打印函数名
def func1(): print(111) print(func1) 结果为:<function func1 at 0x000001B578743E18>
输出结果为函数名在内存中的地址
2 函数名可以作为容器类数据的元素
def func1(): print(111) def func2(): print(222) def func3(): print(333) l1=[func1,func2,func3] for i in l1: i() 结果为: 111 222 333
3 函数名作为函数的参数
def func1(): print("This is func1") def func2(x): print("This is func2")
func2(func1) 结果为:This is func2
4 函数名可以作为函数的返回值
def func1(): print("This is func1") def func2(x): print("This is func2") return x ret=func2(func1) 此行相当于 ret=func1 print(ret) 结果为: This is func2 <function func1 at 0x0000020417DD3E18>
五 闭包函数
1 闭包的定义
内层函数对外层函数非全局变量的引用,就叫做闭包
2 基本的闭包函数示例
def wrapper(): name='qiaofeng' def inner(): print(name) inner()
wrapper()
结果为:qiaofeng
3 检验是否为闭包
通过函数名.__closure__检验,如果结果为空则不是闭包函数
def wrapper(): name='qiaofeng' def inner(): print(name) inner() print('测试__closure__的内存地址为:\n',inner.__closure__) wrapper() 结果为: qiaofeng 测试__closure__的内存地址为: (<cell at 0x00000130C3607468: str object at 0x00000130C369D730>,)
4 用处
如果Python解释器遇到了闭包,他有一个机制,就是这个闭包函数不会随着函数的结束而释放
六 装饰器
需求:测试一个函数的执行效率
定义两个待测的函数
def func1(): time.sleep(0.5) print('测试函数func1的执行时间...')
def func2(): time.sleep(0.3) print('测试函数func2的执行时间...')
#version:0
import time def func1(): time.sleep(0.5) print('测试此函数的执行时间...') start_time=time.time() func1() end_time=time.time() print("此函数的执行时间为:%s" %(end_time-start_time)) 结果为: 测试函数func1的执行时间... 此函数的执行时间为:0.5000154972076416
1 需求:要求封装到一个函数中
import time def timmer(): def func1(): time.sleep(0.5) print('测试函数func1的执行时间...') start_time=time.time() func1() end_time=time.time() print("此函数的执行时间为:%s" %(end_time-start_time)) timmer() 执行结果为: 测试函数func1的执行时间... 此函数的执行时间为:0.5008091926574707
2 需求:被测试函数当参数传入,可以测试多个函数的执行效率
def timmer(f): start_time=time.time() f() end_time=time.time() print("此函数的执行时间为:%s" %(end_time-start_time)) timmer(func1) timmer(func2) 结果为: 测试函数func1的执行时间... 此函数的执行时间为:0.5004558563232422 测试函数func2的执行时间... 此函数的执行时间为:0.3000974655151367
3 需求:测试函数执行效率的同时,不要改变原函数的调用方式
#version:3 def timmer(f): start_time=time.time() f() end_time=time.time() print("此函数的执行时间为:%s" %(end_time-start_time)) f1=func1 func1=timmer #这步相当于把timmer这个函数名赋值给func1 func1(f1) ##这步相当于timmer(func1) 结果为: 测试函数func1的执行时间... 此函数的执行时间为:0.5001800060272217
4 最简单的装饰器
虽然version3大体上满足了我的需求,但是增加两行代码,而且多了个参数,感觉不够好,需要继续改,尽量不要添加其它代码,而且做到调用时一模一样
#version:4 def timmer(f): start_time=time.time() f() end_time=time.time() print("此函数的执行时间为:%s" %(end_time-start_time)) func1=timmer(func1) 结果为: 测试函数func1的执行时间... 此函数的执行时间为:0.5006768703460693
5 语法糖@
版本4每次测试一个函数的执行效率是,都需要加一行func=timmer(func1),麻烦,于是Python提出了一个语法糖 @。
def timmer(f): def inner(): start_time=time.time() f() end_time=time.time() print("此函数的执行时间为:%s" %(end_time-start_time)) return inner @timmer def func1(): time.sleep(0.5) print('测试函数func1的执行时间...') func1() 结果为: 测试函数func1的执行时间... 此函数的执行时间为:0.5005886554718018
6 有参装饰器
被装饰的函数肯定是要有参数的,version5不能满足,必须改造成一个有参装饰器
def timmer(f): def inner(*args,**kwargs): start_time=time.time() f(*args,**kwargs) end_time=time.time() print("此函数的执行时间为:%s" % (end_time - start_time)) return inner @timmer def func1(a,b,name,sex='male'): time.sleep(0.5) print(a,b,name,sex) print('测试函数func1的执行时间...') func1(1,2,name='daozhu') 结果为: 1 2 daozhu male 测试函数func1的执行时间... 此函数的执行时间为:0.5006396770477295
7 带返回值的装饰器
被装饰的函数肯定是要有返回值的,解决这个问题。
def timmer(f): def inner(*args,**kwargs): start_time=time.time() ret=f(*args,**kwargs) end_time=time.time() print("此函数的执行时间为:%s" % (end_time - start_time)) return ret return inner @timmer def func3(a,b,name,sex='male'): time.sleep(0.4) print(a,b,name,sex) print('测试函数func2的执行时间...') func3(1,2,sex='fmale',name='alex') 结果为: 1 2 alex fmale 测试函数func2的执行时间... 此函数的执行时间为:0.4004359245300293
8 完整的装饰器示例
def timmer(f): def inner(*args,**kwargs): start_time = time.time() ret = f(*args,**kwargs) end_time = time.time() print('此函数的执行效率%s' % (end_time - start_time)) return ret return inner @timmer def func1(): ………
装饰器的本质就是闭包函数