python函数命名空间与高阶函数
发布于 2021-04-17 05:24 ,所属分类:知识学习综合资讯
目录
命名空间:
命名空间
加载顺序与取值顺序
作用域
内置函数:globals() locals()
高阶函数(函数的嵌套)
关键字:global nonlocal
函数名的运用
详解
命名空间
(点击查看大图)
Python代码运行的时候:从Python解释器开始执行之后,就在内存中开辟了一个空间,每当遇到一个变量,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的把函数名读入内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。
等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候才关注函数里面有哪些变量,而函数中的变量会储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。
这个“存放名字与值的关系”的空间就叫做命名空间(也叫名称空间)。
命名空间分为下面三个空间(三个空间相互独立):
全局命名空间:直接在py文件中,【除去函数和类内部】的变量,函数名与函数的内存地址的关系 都属于全局命名空间;
局部命名空间:又叫临时命名空间,在函数内部声明的变量会放在局部命名空间;
内置命名空间:python解释器存放的一些内置函数,可以拿来即用的特殊变量,如input,print,list等。
加载顺序与取值顺序
(点击查看大图)
加载顺序
加载顺序就是三个命名空间加载到内存的先后顺序,在启动python解释器之后,即使没有创建任何的变量或函数,还是会有一些函数可以直接用的,比如print(),input()等,在启动Python解释器的时候,就已经导入到内存当中供我们使用,所以是先加载内置命名空间。
然后就开始从文件的最上面向下一行一行执行,此时如果遇到了初始化变量,就会创建全局命名空间,将这些对应关系存放进去,然后遇到了函数执行时,在内存中临时开辟一个空间,加载函数中的一些变量等。
所以这三个空间的加载顺序为:
内置命名空间:程序运行开始加载;
全局命名空间:程序运行中,从上到下加载;
局部命名空间:程序运行中,调用函数时才加载。
取值顺序
取值顺序就是引用一个变量时,先从哪一个空间开始引用。关键点:从哪个空间开始引用这个变量。
在全局命名空间引用一个变量时,先从全局命名空间引用,全局命名空间如果没有,才会向内置命名空间引用。
input = 1
def func():
input = 2
print(input) # 1 在全局命名空间引用一个变量
(左右滑动查看完整代码)
在局部命名空间引用一个变量时,先从局部命名空间引用,局部命名空间如果没有,才会向全局命名空间引用,全局命名空间如果也没有,就会向内置命名空间引用。
input = 1
def func():
input = 2
print(input) # 2 在局部命名空间引用一个变量
func()
(左右滑动查看完整代码)
命名空间的取值顺序与加载顺序是相反的,取值顺序满足就近原则,从小范围到大范围一层一层的逐步引用。
作用域
(点击查看大图)
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置命名空间和全局命名空间,在整个文件的任何位置都可以使用,遵循从上到下逐⾏执行。
局部作用域:包含局部命名空间,在函数内部可以使用。
局部作用域 可以引用 全局作用域的变量,但是不能改变
'''
局部作用域可以引用全局作用域的变量
'''
n = 1
def func():
print(n) # 1 局部作用域引用全局作用域的变量
func()
(左右滑动查看完整代码)
'''
局部作用域不能改变全局作用域的变量
当python解释器读取到局部作用域时,
发现对一个变量进行修改操作,
解释器会认为在局部已经定义过这个局部变量了,
就会从局部找这个局部变量,没找到就报错了
'''
n = 1
def func():
n = 2 # 这个是在局部创建一个新的变量,不是修改全局变量
print(n) # 2
func()
m = 1
def func1():
m += 2 # 在局部修改全局作用域的变量,代码会直接报错
print(m)
func1()
(左右滑动查看完整代码)
'''
在函数中,如果定义了一个变量,
但在定义这个变量之前对其引用了,
那么解释器会认为是语法问题,应该在使用之前先定义
'''
n = 1
def func():
print(n) # 代码会报错
n = 2
func()
(左右滑动查看完整代码)
内置函数:globals()、locals()
(点击查看大图)
globals():以字典的形式返回全局作用域所有的变量对应关系。
locals():以字典的形式返回当前作用域的变量的对应关系。
'''
在全局作用域下打印
globals()和locals()获取的都是全局作用域的所有内容
'''
a = 1
b = 2
print(globals()) # 获取的是全局作用域的所有内容
print(locals()) # 获取的是全局作用域的所有内容
'''
在局部作用域下打印
globals()获取的是全局作用域的所有内容
locals()获取的是局部作用域的所有内容
'''
a = 1
b = 2
def func():
c = 3
print(globals()) # 获取的是全局作用域的所有内容
print(locals()) # {'c': 3} 获取的是局部作用域的所有内容
func()
(左右滑动查看完整代码)
高阶函数(函数的嵌套)
(点击查看大图)
函数的嵌套,就是一个函数中还有函数。
关键点:只要有函数名()就是函数的调用,如果没有就不是函数的调用。
注意点:注意代码的执行顺序。
def fun1():
print(1)
def fun2():
print(2)
print(3)
fun2()
print(4)
print(5)
fun1()
print(6)
# 执行结果:5 1 3 2 4 6
(左右滑动查看完整代码)
关键字global、nonlocal
(点击查看大图)
global
局部作用域对全局作用域的变量(只能是不可变的数据类型)只能进行引用,不能进行改变,只要改变就会报错,如果想在局部作用域中去改变全局作用域的一些变量,可以用关键字global。
global在局部作用域中可以更改全局作用域的变量(仅限字符串,数字)。
n = 1
def func():
global n # global在局部作用域中可以更改全局作用域的变量
n = 2
print(n) # 2
print(n) # 1
func()
print(n) # 2 全局作用域的变量被改变了
(左右滑动查看完整代码)
利用global可以在局部作用域中声明一个全局变量。
def func():
global n # global在局部作用域中声明一个全局变量
n = 2
print(n) # 2
# print(n) # 在声明全局变量之前打印会报错
func()
print(n) # 2
(左右滑动查看完整代码)
nonlocal
nonlocal与global用法差不多,就是在局部作用域中,可以对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。注意:不能更改全局变量。
def func1():
n = 1
def func2():
n = 2
print(n) # 2
def func3():
nonlocal n # func2中的n
n += 1
print(n) # 3
func3()
print(n) # 3
func2()
print(n) # 1
func1()
(左右滑动查看完整代码)
函数名的运用
(点击查看大图)
函数名的定义和变量的定义几乎一样,在变量的角度,函数名其实就是一个变量,具有变量的所有功能;但是作为函数名也有特殊的功能,就是加上() 就会执行对应的函数,所以可以把函数名当做一个特殊的变量。
函数的内存地址
def func():
print(1)
print(func) # <function func at 0x00000246A8965C18>
(左右滑动查看完整代码)
函数名指向的是这个函数的内存地址,与其说函数名()可以执行这个函数,不如说是函数的内存地址()才是执行这个函数的关键。
函数名可以赋值给其他变量
def func():
print(1)
a = func # 把函数名当成一个变量赋值给另一个变量
a() # 函数调用 func()
(左右滑动查看完整代码)
通过变量的赋值,变量a和变量func 都指向的这个函数的内存地址,那么a() 当然可以执行这个函数了。
函数名可以当做容器类的元素
def func1():
print(1)
def func2():
print(2)
def func3():
print(3)
def func4():
print(4)
li = [func1, func2, func3, func4]
for i in li:
i() # 1 2 3 4
(左右滑动查看完整代码)
函数名可以当做函数的参数
def func1():
print(1)
def func2(f):
print(2)
f()
func2(func1) # 2 1
(左右滑动查看完整代码)
函数名可以作为函数的返回值
def func1():
print(1)
def func2(f): # f = func1
print(2)
return f
ret = func2(func1)
ret() # ret, f, func1 都指向func1这个函数的内存地址
(左右滑动查看完整代码)
相关资源