装饰器、闭包、函数名的应用、关键字global、nonlocal、内置函数globals、locals、名称空间、作用域、取值顺序

一、名称空间、作用域
python内存,如果长时间不调用,会自己回收
名称空间:
名称空间
当程序执行时,呆萌从上向下依次运行,会将变量与值的关系存储在一个空间中
这个空间叫  命名空间  名称空间  全局名称空间
临时名称空间
当函数执行时,内存会‘临时’开辟一个空间,存放函数体里面的
代码(变量、代码等)
函数外面访问不到临时空间的内容,随着函数的执行完毕,临时名称空间会释放掉
像这个临时开辟的空间叫临时命名空间,也叫局部名称空间
python中名称空间分三种
内置名称空间
全局名称空间
局部名称空间
作用域
全局作用域
内置名称空间
全局名称空间
局部作用域
局部名称空间
加载顺序
内置名称空间-->全局名称空间-->(当程序执行时) ---> 局部名称空间(当函数调用时)
取值顺序:单向不可逆
局部名称空间(当函数调用时) -->全局名称空间(当程序执行时) -->内置名称空间
函数的嵌套
def func1():
print(666)
def func2():
func1()
print(333)
def func3():
func2()
print(222)
print(111)
func3()
print(555)
111
666
333
222
555
def func1():
name = 'alex'
print(name)
def func2():
name1 = '太白'
print(333)
print(444)
func2()
func1()
alex
444
333
二、内置函数globals、locals
globals():
返回一个字典,字典里面的内容是全局作用域的内容。
locals():
返回一个字典,当前位置的所有变量
name = 'alex'
age = 1000
sex = '男'
def func1():
name1 = 'oldboy'
age = 10000
print(globals())
print(locals())
func1()
print(globals())
print(locals())
def func1():
name1 = 'oldboy'
age = 10000
def func2():
name2 = 'wusir'
age2 = 25
print(globals())
print(locals())
func2()
func1()
三、global、nonlocal
global
报错:UnboundLocalError: local variable 'count' referenced before assign
1 引用并改变一个全局变量
2 在局部作用域声明一个全局变量
count = 1
def func1():
global count
count = count + 1
count = count + 100
print(count)
func1()
print(count)
print(globals())
def func1():
global name
name = 'alex'
print(name)
func1()
print(name)
nonlocal
报错local variable 'count' referenced before assignment
1  不能操作全局变量
2  从那次引用的该变量,从哪层开始全部改变
def func1():
count = 1
def inner():
nonlocal count
count = count + 3
print(count)
def inner2():
   pass
inner()
print(count)
func1()
取值:引用而不是改变
取值是从小到大取值  LEGB
想改变上次空间的变量,要用到 global  nonlocal
对于可改变的数据类型,list  dict  set  不用global  nonlocal
如果默认参数是一个可变的数据类型,那么他在内存中永远是一个
def extendList(val,list=[]):
list.append(val)
return list
list1 = extendList(10)
print('list1=%s'%list1)  # [10,]
list2 = extendList(123,[])
print('list2=%s'%list2)  # [123,]
list3 = extendList('a')
print('list3=%s'%list3)  #[10,'a']
print('list1=%s'%list1)
print('list2=%s'%list2)
print('list3=%s'%list3)
四、函数名的应用
函数名具有可描述性,可以理解为函数名为变量,是特殊的变量,这个变量+()可以执行
1、函数名可以作为容器里数据的元素(列表、字典等数据类型)
def func_1():
pass
….
func = [func_1,fucn_2,func_3]
for I in func:
i()
2、函数名可以作为函数的参数
def func_1(x):
x()
func_1(print)
以上都可以执行print()函数
3、函数名可以作为函数的返回值
def func1():
return 111
def func2(x):  # x = func1
print(222)
return x
ret = func2(func1)  # func1
print(ret())
print(ret)
def func3(x):
print(x)
return x
# a = 2
# func1 = <function func1 at 0x000000000258F9D8>
func3(func1)
def func1():
print(1111)
return 111
f1 = func1
f2 = f1
f3 = f2
print(f3)
f3()
五、闭包
内层函数对外层函数非全局变量的引用,就叫做闭包
def wrapper():
name = 'alex'
def inner():
print(name)
inner()
wrapper()
name = 'alex'
def wrapper():
def inner():
print(name)
inner()
print(inner.__closure__)  # None
wrapper()
通过函数名.__closure__
name = 'alex'
def wrapper(x):
x = name
def inner():
print(x)
inner()
print(inner.__closure__)  # <cell at 0x0000000000130C48: str object at 0x0000000001E8A260>
wrapper(name)
python解释器遇到了闭包,有一个机制
这个闭包不会随着函数的结束而释放
六、装饰器
应用场景
测试函数的执行效率
装饰器使用
import time
def func_1():
time.sleep(1)
print("素还真")
start_time = time.time()
func_1()
end_time = time.time()
print( end_time - start_time )
封装函数
将测试结果封装到函数中,通过参数将检测函数传入到get_time(func_name),这样可以测试多个不同的函数
import time
def func_1():
time.sleep(1)
print("素还真")
def get_time(x):
start_time = time.time()
x()
end_time = time.time()
print( end_time - start_time )
get_time(func_1)
对于项目中的复杂函数,无法拿到,要在整个系统运行时测试,即不改变函数的执行方式
传参方式修改了调用函数方式,不修改函数的执行命令,测试函数的执行时间
f1 = func_1
func_1 = timer
timer(f1)
极简版装饰器
上一步虽然基本满足了要求,但是增加两行代码,而且多了参数,需要继续修改代码,而且做到调用时一模一样
import time
def func_1():
time.sleep(1)
print("张三")
def get_time(x):
def inner():
start_time = time.time()
x()
end_time = time.time()
print( end_time - start_time )
return inner
func_1 = get_time(func_1)
func_1()
提示:只要闭包不关闭就能找到f所代表的值
优化版装饰器
每次去测试函数的执行效率时,都会加一行 func_1 = get_time(func_1)代码,麻烦
python 语法糖 @ 
需要将get_time 放到其他函数上
import time
def get_time(x):
def inner():
start_time = time.time()
x()
end_time = time.time()
print( end_time - start_time )
return inner
@get_time #语法糖的装饰器 相当于 func_1 = get_time(func_1)
def func_1():
time.sleep(1)
print("张三")
func_1()
被装饰的函数指定要有参数,现在不能满足,解决问题
def get_time(x):
def inner(*args,**kwargs): #args = (1,2),kwargs = {'sex':'man','name':'张三'}
start_time = time.time()
x(*args,**kwargs) #此时函数打散 func_2(1,2,sex='man',name='张三')
end_time = time.time()
print( end_time - start_time )
return inner
@get_time
def func_2(a,b,name,sex):
time.sleep(.1)
print(a,b,name,sex)
func_2(1,2,sex='man',name='张三')
被装饰的函数带参数且有返回值的,解决这个问题
import time
def get_time(x):
def inner(*args,**kwargs): #args = (1,2),kwargs = {'sex':'man','name':'素还真'}
start_time = time.time()
return_name = x(*args,**kwargs) #此时函数打散 func_2(1,2,sex='man',name='素还真')
end_time = time.time()
print( end_time - start_time )
return return_name
return inner
@get_time
def func_2(a,b,name,sex):
time.sleep(.1)
print(a,b,name,sex)
return name
print(func_2(1,2,sex='man',name='张三'))
9.2.8 终极版装饰器
def get_time(x):
def inner(*args,**kwargs): #args = (1,2),kwargs = {'sex':'man','name':'素还真'}
start_time = time.time()
‘’‘ 被装饰函数执行之前的操作 ’‘’
return_name = x(*args,**kwargs) #此时函数打散 func_2(1,2,sex='man',name='素还真')
‘’‘ 被装饰函数执行之后的操作 ’‘’
end_time = time.time()
print( end_time - start_time )
return return_name
return inner
@get_time
def func_2(a,b,name,sex):
time.sleep(.1)
print(a,b,name,sex)
return name
print(func_2(1,2,sex='man',name='张三'))
装饰器解释
装饰器本质是闭包
装饰器根本作用,在不影响原函数执行的基础上,增加一些额外的功能,登录认证,打印日志等

猜你喜欢

转载自www.cnblogs.com/dunkeng/p/9119185.html
今日推荐