python函数命名空间与高阶函数

发布于 2021-04-17 05:24 ,所属分类:知识学习综合资讯


目录

命名空间:

命名空间

加载顺序与取值顺序

作用域

内置函数:globals() locals()

高阶函数(函数的嵌套)

关键字:global nonlocal

函数名的运用




详解

命名空间

(点击查看大图)



Python代码运行的时候:从Python解释器开始执行之后,就在内存中开辟了一个空间,每当遇到一个变量,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的把函数名读入内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。


等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候才关注函数里面有哪些变量,而函数中的变量会储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。


这个“存放名字与值的关系”的空间就叫做命名空间(也叫名称空间)。


命名空间分为下面三个空间(三个空间相互独立):

  • 全局命名空间:直接在py文件中,【除去函数和类内部】的变量,函数名与函数的内存地址的关系 都属于全局命名空间;

  • 局部命名空间:又叫临时命名空间,在函数内部声明的变量会放在局部命名空间;

  • 内置命名空间:python解释器存放的一些内置函数,可以拿来即用的特殊变量,如input,print,list等。




加载顺序与取值顺序

(点击查看大图)



加载顺序


加载顺序就是三个命名空间加载到内存的先后顺序,在启动python解释器之后,即使没有创建任何的变量或函数,还是会有一些函数可以直接用的,比如print(),input()等,在启动Python解释器的时候,就已经导入到内存当中供我们使用,所以是先加载内置命名空间。


然后就开始从文件的最上面向下一行一行执行,此时如果遇到了初始化变量,就会创建全局命名空间,将这些对应关系存放进去,然后遇到了函数执行时,在内存中临时开辟一个空间,加载函数中的一些变量等。


所以这三个空间的加载顺序为:

  • 内置命名空间:程序运行开始加载;

  • 全局命名空间:程序运行中,从上到下加载;

  • 局部命名空间:程序运行中,调用函数时才加载。




取值顺序


取值顺序就是引用一个变量时,先从哪一个空间开始引用。关键点:从哪个空间开始引用这个变量。


全局命名空间引用一个变量时,先从全局命名空间引用,全局命名空间如果没有,才会向内置命名空间引用。

input = 1def func():  input = 2print(input) # 1 在全局命名空间引用一个变量

(左右滑动查看完整代码)



局部命名空间引用一个变量时,先从局部命名空间引用,局部命名空间如果没有,才会向全局命名空间引用,全局命名空间如果也没有,就会向内置命名空间引用。

input = 1def func():  input = 2  print(input) # 2 在局部命名空间引用一个变量func()

(左右滑动查看完整代码)



命名空间的取值顺序与加载顺序是相反的,取值顺序满足就近原则,从小范围到大范围一层一层的逐步引用。




作用域

(点击查看大图)



作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。


全局作用域:包含内置命名空间和全局命名空间,在整个文件的任何位置都可以使用,遵循从上到下逐⾏执行。


局部作用域:包含局部命名空间,在函数内部可以使用。



局部作用域 可以引用 全局作用域的变量,但是不能改变

'''局部作用域可以引用全局作用域的变量'''
n = 1def func(): print(n) # 1 局部作用域引用全局作用域的变量func()

(左右滑动查看完整代码)



'''局部作用域不能改变全局作用域的变量
当python解释器读取到局部作用域时,发现对一个变量进行修改操作,解释器会认为在局部已经定义过这个局部变量了,就会从局部找这个局部变量,没找到就报错了'''
n = 1def func(): n = 2 # 这个是在局部创建一个新的变量,不是修改全局变量 print(n) # 2func()

m = 1def func1(): m += 2 # 在局部修改全局作用域的变量,代码会直接报错 print(m)func1()

(左右滑动查看完整代码)



'''在函数中,如果定义了一个变量,但在定义这个变量之前对其引用了,那么解释器会认为是语法问题,应该在使用之前先定义'''
n = 1def func(): print(n) # 代码会报错 n = 2func()

(左右滑动查看完整代码)




内置函数:globals()、locals()

(点击查看大图)



globals():以字典的形式返回全局作用域所有的变量对应关系。


locals():以字典的形式返回当前作用域的变量的对应关系。


'''在全局作用域下打印globals()和locals()获取的都是全局作用域的所有内容'''a = 1b = 2print(globals()) # 获取的是全局作用域的所有内容print(locals()) # 获取的是全局作用域的所有内容

'''在局部作用域下打印globals()获取的是全局作用域的所有内容locals()获取的是局部作用域的所有内容'''a = 1b = 2def 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 = 1def func():  global n # global在局部作用域中可以更改全局作用域的变量  n = 2  print(n) # 2
print(n) # 1func()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)  # 1func1()

(左右滑动查看完整代码)




函数名的运用

(点击查看大图)



函数名的定义和变量的定义几乎一样,在变量的角度,函数名其实就是一个变量,具有变量的所有功能;但是作为函数名也有特殊的功能,就是加上() 就会执行对应的函数,所以可以把函数名当做一个特殊的变量。



函数的内存地址

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这个函数的内存地址

(左右滑动查看完整代码)




相关资源