函数的名称空间和作用域
命名空间
一、什么是python的名称空间
名称到对象的映射。命名空间是一个字典的实现,键为变量名,值是变量对应的值。各个命名空间是独立没有关系的,一个命名空间中不能有重名,但是不同的命名空间可以重名而没有任何影响。
通俗讲:名称空间就是存放名字的地方,三种名称空间,(之前遗留的问题x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方)
原文链接:https://blog.csdn.net/lmseo5hy/article/details/80353099
二、名称空间的分类
- 内置名称空间 (Built-in)
存放着python的内置名称,如内置语言的名称如 len,char 和一些异常的名称 BaseException等,在任何模块都可以被调用,且随着python解释器的启动而产生,关闭而回收,因此它是第一个被加载的名称空间.
>>> len <built-in function len>
- 全局名称空间
模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量,伴随着python文件的执行而产生
- 局部名称空间
函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量,只有调用函数时才会产生,调用完成时便会被回收
>>> def func(): ... a = 1 ... >>> a Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'a' is not defined >>>
三、命名空间的加载顺序
内置命名空间(程序运行前加载)-->全局命名空间(程序运行中:从上到下加载)-->局部命名空间(程序运行中:调用时才加载)
四、命名空间的查找顺序
局部的命名空间--> 全局命名空间 -> 内置命名空间。
当这三个命名空间还找不到时,会抛出NameError 异常
函数的作用域
作用域就是一个 Python 程序可以直接访问命名空间的正文区域。
在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。
一、四种作用域和查找顺序
- L(Local):最内层,包含局部变量,比如一个函数/方法内部。
- E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
- G(Global):当前脚本的最外层,比如当前模块的全局变量。
- B(Built-in): 包含了内建的变量/关键字等。,最后被搜索
所以查找顺序为 : L –> E –> G –> B
二、全局变量和局部变量
- 全局变量 : 定义在函数外的拥有全局作用域,在整个文件执行过程中都存在,任意位置都能调用(创建类的另说)
- 局部变量 : 只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用
#!/usr/bin/env python # -*- coding: utf-8 -*- total = 0 # 这是一个全局变量 def sum(x, y): # 返回2个参数的和." total = x + y # total在这里是局部变量. print("函数内是局部变量 : ", total) return total sum(1, 2) print("函数外是全局变量 : ", total) """ 函数内是局部变量 : 3 函数外是全局变量 : 0 """
三、global 和 nonlocal 关键字
当我们想在内部作用域修改外部作用域的变量时,可以使用 global 和 nonlocal 关键字.
- global 关键字 : 修改全局变量
#!/usr/bin/env python # -*- coding: utf-8 -*- total = 0 # 这是一个全局变量 def sum(x, y): # 返回2个参数的和." global total total = x + y # total在这里是局部变量. print("函数内是局部变量 : ", total) return total sum(1, 2) print("函数外是全局变量 : ", total) """ 函数内是局部变量 : 3 函数外是全局变量 : 3 """
- nonlocal关键字 : 修改嵌套作用域(enclosing 作用域,外层非全局作用域),如果嵌套了多层函数,nonlocal 会从当前函数的上一层函数开始一层层查找,知道找到最外层,若没找到,则会抛出异常
def func1(): # 返回2个参数的和." a = 1 print("start a : ", a) def func2(): b = 2 def func3(): nonlocal a a = 3 func3() func2() print("end a : ", a) func1() """ start a : 1 end a : 3 """
四、局部变量引用问题
a = 1 def test(): a = a + 1 print(a) test() """ UnboundLocalError: local variable 'a' referenced before assignment """
这是因为在函数内部对变量赋值进行修改后,该变量就会被Python解释器认为是局部变量而非全局变量,当程序执行到a=a+1的时候,因为这条语句是给a赋值,所以a成为了局部变量,那么在执行return a(或是print a)的时候,因为a这个局部变量还没有定义,自然就会抛出这样的错误。
解决这个问题可以有以下几种方法:
1. 在函数内部声明global a
2.在函数内部重新定义一个a变量
3.通过函数传递参数