一、命名空间
命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的;
命名空间提供了项目中避免名字冲突的一种方法,各个命名空间是独立没有任何关系的,因此一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响;如Windows系统一个目录下文件名不能重名,但不能目录下文件可重名
Python中一般有三种命名空间:
- 内置名称(bulit-in names):Python语言的内置名称,如函数名 abs、char 和异常名称 BaseException、Exception 等
- 全局名称(global names):模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量等
- 局部名称(local names):函数或类中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量等
命名空间的范围大小:内置名称>全局名称>局部名称
命名空间的查找顺序:局部命名空间 -> 全局命名空间 -> 内置命名空间,如果均找不到,报错NameError 异常:
NameError: name 'xxx' is not defined
命名空间的生命周期:命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。因此,我们无法从外部命名空间访问内部命名空间的对象
二、作用域
作用域就是一个 Python 程序可以直接访问命名空间的正文区域;
Python 程序中,访问一个变量会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误;
Python的作用域一共有4种,分别为:
- L(Local):最内层,包含局部变量,比如一个函数/方法内部
- E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal;
- G(Global):当前脚本的最外层,比如当前模块的全局变量;
- B(Built-in): 包含了内建的变量/关键字等,最后被搜索
规则顺序: L –> E –> G –> B
内置作用域是通过一个名为 builtin 的标准模块来实现的,但这个变量名自身并没有放入内置作用域内,所以必须导入这个模块才能够使用它。Python3.0中,可以使用如下代码查看到底预定义了哪些变量:
import builtins
dir(builtins)
Python 中只有模块(module)、类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,即这些语句内定义的变量,外部也可以访问;
三、全局变量和局部变量
全局变量:定义在函数外的变量,全局变量可以在整个程序范围内访问;
局部变量:定义在函数内的变量,局部变量只能在其被声明的函数内部访问;
调用函数时,所有在函数内声明的变量名称都将被加入到作用域中;
# 1、全局变量和局部变量
# 定义全局变量
globalvalue = 0
def sum(arg1, arg2):
#globalvalue在函数里是局部变量
globalvalue = arg1 + arg2
print("函数内是局部变量 : " , globalvalue)
return globalvalue
# 调用sum函数
sum(10, 20)
print("函数外是全局变量 : ", globalvalue)
函数内是局部变量 : 30
函数外是全局变量 : 0
四、global 和 nonlocal关键字
global 和 nonlocal关键字主要用于内部作用域需要修改外部作用域的变量;global 关键字主要用于局部变量修改全局变量;nonlocal关键字主要用于修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量
# global 关键字主要用于局部变量修改全局变量
# 全局变量num
num = 1
def fun1():
global num #需要使用 global 关键字声明
print("输出修改前全局变量值:" , num) #输出修改前全局变量值
num = 123 #局部作用域修改全局变量的值
print("输出修改后全局变量值:" , num) #输出修改后全局变量值
# 函数调用
fun1()
# 全局变量值已被修改
print("全局变量值已被修改:" , num)
# global 关键字主要用于局部变量修改全局变量
def outer():
num = 10 # 局部变量,enclosing 作用域
# 函数嵌套
def inner():
nonlocal num # nonlocal关键字声明
num = 100 # 修改enclosing 作用域的值
print("inner函数输出修改后的值:" , num) # 输出修改后的值
inner()
print("num已被修改:" , num)
outer()
输出修改前全局变量值: 1
输出修改后全局变量值: 123
全局变量值已被修改: 123
inner函数输出修改后的值: 100
num已被修改: 100