函数二----函数的进阶
一、命名空间(有三种)
1.内置的命名空间 -----python解释器
就是python解释器一启动就可以使用的名字存储再内置的命名空间中
内置的名字在启动解释器的时候被加载进内存里。
2.全局命名空间 -----我们写的代码,但不是函数中的代码
是在程序从上到下被执行的过程中依次加载进内存的
放置了我们设置的所有变量名和函数名
3.局部命名空间 -----函数
就是函数内部定义的名字
当调用函数的时候,才会产生这个名称空间,随着函数执行的结束,这个命名空间就又消失了
三种命名空间之间的加载顺序:
内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
#在局部:可以使用全局、内置命名空间中的名字
#在全局:可以使用内置命名空间中的名字,但是不能用局部中命名空间中的名字
#在内置:不能使用全局、局部命名空间中的名字
def func(): a = 1 func() print(a) #因为全局没有a这个变量,它不可能去找func函数里的这个a变量,所以会报错
#在正常情况下,直接使用内置的名字
#当我们在全局定义了和内置名字空间中同名的名字时,会使用全局的名字
#当我自己有的时候,我就不找我的上级要了
#如果自己没有,就找上一级要,上一级没有再找上一级,如果内置的名字空间都没有,就报错
#多个函数应该拥有多个独立的局部命名空间,不互相共享
def input(): print('in input now') def func(): # input = 1 print(input) func() # <function input at 0x0000028967220378> ---函数的内存地址() #func ---> 函数的内存地址 #函数名() --->函数的调用 #函数的内存地址() --->函数的调用
二、作用域
#全局作用域 ---作用在全局 ---内置和全局名字空间中的名字都属于全局作用域---globals()
#局部作用域 --- 作用在局部 --- 函数(局部名字空间中的名字属于局部作用域)---locals可以查看
a = 1 def func(): return a print(func()) # 1 a = 1 def func(): global a a += 1 func() print(a) #2 func() print(a) #3 a = 1 def func(a): a = 2 return a a = func(a) print(a) #2
#对于不可变数据类型,在局部可以查看全局作用域中的变量,但是不能直接修改
#如果想要修改,需要在程序的一开始添加global声明
#如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局变量有效
a = 1 b = 2 def func(): x = 'aaa' y = 'bbb' print(locals()) # {'x': 'aaa', 'y': 'bbb'} print(globals()) func() print(globals()) print(locals()) #本地的,放在全局,全局就是本地;放在局部,局部就是本地
#globals 永远打印全局的名字
#locals 输出什么,根据locals所在的位置
三、函数的嵌套及作用域链
函数的嵌套使用
def max(a,b): return a if a > b else b def the_max(x,y,z): c = max(x,y) return max(c,z) print(the_max(1,2,3)) # 3
函数的嵌套定义
def outer(): def inner(): print('inner') inner() outer() #inner
内部函数可以使用外部函数的变量
def outer(): a = 1 def inner(): b = 2 print(a) print('inner') def inner2(): print(a,b) print('inner2') inner2() inner() outer()
def outer(): a = 1 def inner(): b = 2 print(a) print('inner') def inner2(): nonlocal a #声明了一个上面层离它最近的一个局部变量 a += 1 #不可变数据类型的修改 print('inner2') inner2() inner() outer() #nonlocal 只能用于局部变量,找上层中离当前函数最近一层的局部变量,内部声明了nonlocal的内部函数的变量修改会影响到离当前函数最近一层的局部变量 #nonlocal 对全局无效,对局部也只是对最近含有此变量的一层有影响
a = 1 def outer(): a = 10 def inner(): # a = 20 def inner2(): nonlocal a a += 1 inner2() print('**a** :',a) inner() print('##a## :',a) outer() print('全局:',a)
#在内部函数使用变量的时候,是从小局部到大局部到内置名字的过程,
# 一级一级往上找,找到最近的一个就使用----作用域链
四、函数名的本质
函数名本质上就是函数的内存地址
1.可以被引用
def func(): print('in func') f = func print(f) #<function func at 0x0000017628CD0378>
2.可以被当做容器类型的元素
def f1(): print(1) def f2(): print(2) def f3(): print(3) l = [f1,f2,f3] d = {'f1':f1,'f2':f2,'f3':f3} l[0]() # 1 d['f3']() # 3
3.可以当做函数的参数和返回值
def func(): print(123) def wahaha(f): f() wahaha(func) #函数名可以作为函数的参数 def func(): print(123) def wahaha(f): f() return f #函数名可以作为函数的返回值 qqxing = wahaha(func)
五、闭包
闭包函数:内部函数包含外部作用域而非全局作用域名字的引用,该内部函数称为闭包函数
函数内部定义的函数称为内部函数
判断闭包函数的方法__closure__
def outer(): a = 1 def inner(): print(a) print(inner.__closure__) outer() print(outer.__closure__) # def outer(): # a = 1 # def inner(): # print(a) # return inner # inn = outer() # inn()
import urllib #模块 from urllib.request import urlopen def get_url(): url = 'http://www.xiaohua100.cn/index.html' def inner(): ret = urlopen(url).read() print(ret) return inner get_func = get_url() get_func()