本节内容:函数的进阶、闭包、装饰器
1.名称空间
2.作用域
3.取值顺序
4.函数的嵌套
5.内置函数
6.关键字
7.函数的应用
8.闭包
9.装饰器
1、名称空间
1.1 名称空间
当程序运行时,代码从上之下一次执行,他会将变量与值的关系存储在一个空间中,这个空间叫做名称空间,命名空间,全局名称空间。
1.2 局部名称空间
当程序遇到函数时,他会将函数名存在内存中,函数体莫不关心。
当函数执行时,内存会临时开辟一个空间,存放函数体里面的代码(变量,代码等),
函数外面访问不到临时空间的内容,随着函数的执行完毕,临时名称空间会释放掉,
向这个临时开辟的空间叫临时名称空间,也叫局部名称空间。
1.3 Python中名称空间种类
内置名称空间。
全局名称空间。
局部名称空间。
2、作用域
2.1 全局作用域
内置名称空间
全局名称空间
2.2 局部作用域
局部名称空间
2.3 加载顺序
内置名称空间 ---> 全局名称空间(当程序执行时) ---> 局部名称空间(当函数调用时)
3、取值顺序
取值顺序:单向不可逆
局部名称空间(当函数调用时) -->全局名称空间(当程序执行时) -->内置名称空间
3.1 先从局部找
name1 = 'oldboy' def func2(): name1 = 'alex' print(name1) func2() =====>输出 alex
3.2 再从全局找
name1 = 'oldboy' def func2(): print(name1) func2() =====>输出 oldboy
3.3 最后从内置空间找
def func2(): print(input) func2() =====>输出 <build-in function input>
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
5、内置函数
5.1 globals()
返回一个字典,字典里面的内容是全局作用域的内容。
name = 'alex' age = 1000 sex = '男' def func1(): name1 = 'oldboy' age = 10000 func1() print(globals()) print(locals()) =========>输出 None, 'name': 'alex', 'age': 1000, 'sex': '男', 'func1': <function func1 at 0x0000000001CF2E18>} None, 'name': 'alex', 'age': 1000, 'sex': '男', 'func1': <function func1 at 0x0000000001CF2E18>}
5.2 locals()
返回一个字典,当前位置 的所有变量。
def func1(): name1 = 'oldboy' age = 10000 def func2(): name2 = 'wusir' age2 = 25 print(globals()) print(locals()) func2() func1() =====>输出 None, 'func1': <function func1 at 0x0000000001D02E18>} {'age2': 25, 'name2': 'wusir'}
6、关键字
6.1 global
6.1.1 引用并改变一个全局变量
count = 1 def func1(): global count count = count + 1 # count = count + 100 print(count) func1() print(count) =====>输出 2 2
6.1.2 在局部作用域声明一个全局变量
def func1(): global name name = 'alex' print(name) func1() print(name) =====>输出 alex alex
6.2 nonlocal
1、不能操作全局变量
从哪层引用的该变量,从那层开始全部改变。
def func1(): count = 1 def inner(): nonlocal count count = count + 3 print(count) def inner2(): pass inner() print(count) func1() =====>输出 4 4
list = [] def func1(): list.append(666) func1() print(list) =====>输出 [666]
3、如果默认参数是一个可变的数据类型,那么他在内存中永远是一个
def extendList(val,list=[]): list.append(val) return list list1 = extendList(10) print('list1=%s'%list1) list2 = extendList(123,[]) print('list2=%s'%list2) list3 = extendList('a') print('list3=%s'%list3) print('list1=%s'%list1) print('list2=%s'%list2) print('list3=%s'%list3) =======>输出 list1=[10] list2=[123] list3=[10, 'a'] list1=[10, 'a'] list2=[123] list3=[10, 'a']
7、函数名的应用
def func1(): print(666) 1 打印函数名 print(func1) # <function func1 at 0x000000000258F9D8> 2 函数名可以作为容器类数据的元素 def func1(): print(111) def func2(): print(222) def func3(): print(333) l1 = [func1, func2, func3] for i in l1: i() 3 函数名可以作为函数的参数 def func1(): print(111) def func2(x): print(x) x() print(222) func2(func1) 4 函数名可以作为函数的返回值 def func1(): return 111 def func2(x): # x = func1 print(222) return x ret = func2(func1) # func1 print(ret()) print(ret)
7.1 第一类对象
def func3(x): print(x) return x def func1(): print(1111) return 111 f1 = func1 f2 = f1 f3 = f2 print(f3) f3() =========>输出 <function func1 at 0x00000000025120D0> 1111
8、闭包
内层函数对外层函数非全局变量的引用,就叫做闭包。
def wrapper(): name = 'alex' def inner(): print(name) inner() wrapper() ======>输出 alex ======= name = 'alex' def wrapper(): def inner(): print(name) inner() print(inner.__closure__) # None wrapper() =======>输出 alex None
8.1 通过函数名.__closure__
name = 'alex' def wrapper(x): x = name def inner(): print(x) inner() print(inner.__closure__) wrapper(name) =====>输出 alex (<cell at 0x0000000001E16498: str object at 0x000000000049C110>,)
import time print(time.time()) def func1(): time.sleep(0.3) print('非常复杂......') start_time = time.time() func1() end_time = time.time() print('此函数的执行效率%s' %(end_time-start_time)) ===========>输出 1527471870.8405445 非常复杂...... 此函数的执行效率0.3000171184539795 ============== # 改版1:我要封装到一个函数中 import time print(time.time()) def func1(): time.sleep(0.3) print('非常复杂......') def func2(): time.sleep(0.3) print('特别复杂......') func1() func2() ========>输出 1527471978.33138 非常复杂...... 特别复杂...... ============== # 改版2:被测试函数当参数传入,可以测试多个函数的执行效率 def timmer(f): start_time = time.time() f() end_time = time.time() print('此函数的执行效率%s' %(end_time-start_time)) timmer(func1) timmer(func2) ================= 改版3::测试函数执行效率的同时,不要改变原函数的调用方式。 def func1(): time.sleep(0.3) print('非常复杂......') def func2(): time.sleep(0.3) print('特别复杂......') # func1() # func2() def timmer(f): start_time = time.time() f() end_time = time.time() print('此函数的执行效率%s' % (end_time - start_time)) f1 = func1 func1 = timmer # func1(f1) # timmer(func1) ================= 改版4::改版3虽然大体上满足了我的要求,但是增加两行代码, 而且多了参数,不好,继续改,尽量不添加其他代码,而且做到调用时一模一样 最简单的装饰器。 def func1(): time.sleep(0.3) print('非常复杂......') def func2(): time.sleep(0.3) print('特别复杂......') # func1() # func2() def timmer(f): # f = func1 函数名 def inner(): start_time = time.time() f() end_time = time.time() print('此函数的执行效率%s' % (end_time - start_time)) return inner func1 = timmer(func1) # inner func2 = timmer(func2) # inner func1() # inner() func2() ======================== 改版5::改版4每次测试一个函数的执行效率时,都需要加一行 func1 = timmer(func1)代码,麻烦 python提出了一个语法糖 @。 def timmer(f): # f = func1 函数名 def inner(): start_time = time.time() f() end_time = time.time() print('此函数的执行效率%s' % (end_time - start_time)) return inner @timmer # func1 = timmer(func1) inner def func1(): time.sleep(0.3) print('非常复杂......') func1() # inner() ======================== 改版6:被装饰的函数肯定要有参数的,你现在不能满足,解决这个问题。 被装饰的函数带参数的装饰器 def timmer(f): # f = func1 函数名 def inner(*args,**kwargs): # args = (1,2),kwargs {sex:'nv',name:'alex'} start_time = time.time() f(*args,**kwargs) # f(1,2,,sex='nv',name='alex') end_time = time.time() print('此函数的执行效率%s' % (end_time - start_time)) return inner @timmer # func1 = timmer(func1) inner def func1(a,b): time.sleep(0.3) print(a,b) print('非常复杂......') @timmer # func1 = timmer(func1) inner def func2(a,b,name,sex='man'): # f(1,2,,sex='nv',name='alex') time.sleep(0.3) print(a,b,sex,name) print('非常复杂......') func2(1,2,sex='nv',name='alex') # inner() ==================== 改版7:被装饰的函数肯定要有返回值的,解决这个问题。 被装饰的函数带参数且有返回值的装饰器 def timmer(f): # f = func2 函数名 def inner(*args,**kwargs): # args = (1,2),kwargs {sex:'nv',name:'alex'} start_time = time.time() ret = f(*args,**kwargs) # f(1,2,,sex='nv',name='alex') end_time = time.time() print('此函数的执行效率%s' % (end_time - start_time)) return ret return inner @timmer # func1 = timmer(func1) inner def func2(a,b,name,sex='man'): # f(1,2,,sex='nv',name='alex') time.sleep(0.3) print(a,b,sex,name) print('非常复杂......') return 666 print(func2(1,2,sex='nv',name='alex')) # inner() 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 func2(a,b,name,sex='man'): time.sleep(0.3) print(a,b,sex,name) print('非常复杂......') return 666 ret1 = func2(1,2,sex='nv',name='alex') print(ret1) def wrapper(f): def inner(*args,**kwargs): """被装饰函数执行之前的操作""" ret = f(*args,**kwargs) """被装饰函数执行之后的操作""" return ret return inner