函数对象、函数嵌套、名称空间与作用域
一. 函数对象
#函数是第一类对象,函数是第一类对象可以被传递 1.可以被引用 2.可以当作参数被传递 3.返回值可以是函数 4.可以作为容器对象的元素
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def func1(): print("hello,world!") f = func1 f()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def func1(): print("hello,world!") def func2(f): tmp_f = f tmp_f() func2(func1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def outer(): def inter(): print("hello, world") return inter b = outer() b()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def outer(): def inter(): print("hello, world") return inter a = [1,2,3, outer] a[3]()() #a[3]()得到inter函数,再加个括号就是调用inter
二. 函数的嵌套
1. 函数的嵌套调用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def sum_(lst): for i,v in enumerate(lst): lst[i] = v + 10 def is_num(lst): for i in lst: if not isinstance(i, int): return None else: sum_(lst) return lst a = [1, 2, 3, 4, 5, 6] print(is_num(a)) def max(x,y): return x if x>y else y def max4(a,b,c,d): ret = max(a,b) ret2 = max(ret,c) ret3 = max(ret2,d) return ret3 print(max4(1,2,3,4))
2. 函数的嵌套定义
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def outer(): def inner(): #二层嵌套 print("inner") def inner2(): print("inner") inner2() inner()
三. 名称空间和作用域
1.什么是名称空间
#名称空间:存放名字的地方,三种名称空间,内部名称空间,全局名称空间,局部名称空间, (之前遗留的问题x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方) #内置的命名空间-------python解释器 就是Python解释器已启动就可以使用的名字,存储在内置命名空间中 内置的名字在启动解释器的时候被加载进内存里 #全局命名空间--------在函数外定义的, 是在程序从上到下被执行的过程中依此加载进内存的 放置了我们设置的所有变量名和函数名 #局部命名空间---------函数 定义在函数内部的名字 当调用函数的时候,才会产生这个命名空间,随着函数的调用结束,这个命名空间就消失了。
2.名称空间加载顺序
python test.py #1.python启动解释器,首先加载的是内置名称空间 #2.执行test.py,以文件为基础,加载全局名称空间 #3.程序运行时,加载函数,会临时加载局部名称空间
3.名字的查找顺序
#局部 > 全局 > 内置 在局部 可以使用全局,内置命名空间中的名字 在全局 可以使用内置命名空间中的名字,不能使用局部命名空间中的名字 在内置 不能使用局部和全局命名空间中的名字
4.作用域
#1. 作用域就是范围 - 全局范围(内置名称空间和全部命名空间属于这个范围):全局存活,全局有效 - 局部范围(局部名称空间属于这个范围):函数调用时临时存活,结束销毁,局部有效 全局作用域-------------globals()#查看全局作用域的名字 作用在全局,内置和全局命名空间中的名字都属于全局作用域 局部作用域------------locals() # 查看局部作用域的名字 作用在局部,函数(局部命名空间中的名字属于局部作用域) #2.注意事项 对于不可变数据类型,在局部可以查看全局作用域中的变量 但是不能直接修改 如果想要修改,需要在程序的一开始添加global声明 如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效。 不要随意使用gloabl! #3、查看作用域:globals(),locals() globals() 永远打印全局的名字 loacls() 输出什么,取决于loacls所在的位置。 LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__ locals 是函数内的名字空间,包括局部变量和形参 enclosing 外部嵌套函数的名字空间(闭包中常见) globals 全局变量,函数定义所在模块的名字空间 builtins 内置模块的名字空间
5. global和nonlocal关键字
global #只会影响全部变量,不会影响局部变量 nonlocal #只能用于局部变量,找上层中离当前函数最近一层的局部变量 #声明了nonlocal的内部函数的变量修改会影响到离当前最近一层的局部变量
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
a = 1 def outer(): a = 2 def inner(): print("inner:",a) def inner2(): nonlocal a #nolocal关键字定义之后,会影响上层局部作用域中的a,如果上层中没有a,会继续往上层找。 a+=1 print("inner2:",a) inner2() inner() print("outer:",a) outer() print("global",a) #结果 i#nner: 2 #inner2: 3 #outer: 3 #global 1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
a = 1 print("global1:",a) def func1(): a = 2 print("func1:",a) def func2(): global a a += 3 print("func2:",a) func2() func1() print("global2:",a)
四. 闭包函数
1.什么是闭包
#内部函数包含外部作用域且非全局作用域的引用 def counter(): n = 0 def add(): nonlocal n x = n n += 1 return x return add c = counter() print(c()) print(c()) print(c())
2. 闭包的应用与意义
#闭包的意义,返回的函数对象,已经不仅仅是普通的对象了,该函数还包含着外层的一个作用域,使函数在何处调用都是使用自己外层包裹的作用域 from urllib.request import urlopen def index(url): def get(): return urlopen(url).read() return get url = "http://www.baidu.com" f = index("http://www.baidu.com") print(f().decode("utf-8"))