Python语法(高级语法)- 命名空间和作用域
命名空间(Namespace)
- 命名空间是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。
- 命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,对象在同一个命名空间中不能有重名,但不同的命名空间可以重名。
命名空间的类型
- 内置名称(built-in names),
- 比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
- 可以通过下面的方法查看内置名称:
>>> import builtins
>>> dir(builtins)
- 全局名称(global names)
- 模块中定义的名称,包括函数、类、其它导入的模块、模块级的变量和常量。
- 局部名称(local names),
- 类中定义的名称,包括数据属性,方法属性。
- 函数中定义的名称,包括函数的参数、局部定义的变量。
命名空间的查找顺序
- 局部的命名空间去 -> 全局命名空间 -> 内置命名空间
命名空间的生命周期
- 取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。
对象的作用域
- 作用域就是一个Python程序可以直接访问命名空间的正文区域。
- 在一个python程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。
- Python中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。
-
只有模块(module)、类以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的。
var_f0 = 789
while (var_f0 == 789):
print("change var_f0......")
var_f0 = 123123 # 在while中更新var_f0的值
print(var_f0)
输出:
change var_f0......
123123
作用域的类型
- L(Local):最内层,包含局部变量。
- 比如一个函数/方法内部。
- E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。
- 比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
- G(Global):当前脚本的最外层。
- 比如当前模块的全局变量。
- B(Built-in): 包含了内建的变量/关键字等。最后被搜索
作用域的查找顺序
- L –> E –> G –> B
全局变量和局部变量
- 全局变量:定义在函数外的变量具有全局作用域。
- 变量定义在模块的函数外,则在模块内具有全局作用域。
- 变量定义在类内的函数外,则在类内具有全局作用域。
- 局部变量:定义在函数内的变量具有函数内的局部作用域。
global 和 nonlocal关键字
- 当内部作用域想修改外部作用域的变量时,需要用到global和nonlocal关键字。
用例1:在局部作用域中没有同名变量时,可以访问外部变量
# 全局变量,作用域:整个模块。
var_f0 = 123
def func1():
# 局部变量,作用域:func1
var_f1 = 456
def func2():
print("in func2 start......")
print("var_f0:", var_f0) # 在func2中可以访问外部变量
print("var_f1:", var_f1) # 在func2中可以访问外部变量
print("in func2 end......")
print("before func2: ")
print("var_f0:", var_f0)
print("var_f1:", var_f1)
func2()
print("after func2: ")
print("var_f0:", var_f0)
print("var_f1:", var_f1)
func1()
输出:
before func2:
var_f0: 123
var_f1: 456
in func2 start......
var_f0: 123
var_f1: 456
in func2 end......
after func2:
var_f0: 123
var_f1: 456
用例2:在局部作用域中不能直接修正外部变量
# 全局变量,作用域:整个模块。
var_f0 = 123
def func1():
# 局部变量,作用域:func1
var_f1 = 456
def func2():
print("in func2 start......")
print("var_f0:", var_f0) # 在func2中不可以访问
print("var_f1:", var_f1) # 在func2中不可以访问
var_f0 = 789 # 这并不是在给模块变量var_f0赋值,而是在内部重新定义了同名变量,导致print("var_f0:", var_f0)出错。
var_f1 = 789 # 这并不是在给模块变量var_f1赋值,而是在内部重新定义了同名变量,导致print("var_f1:", var_f1)出错。
print("in func2 end......")
print("before func2: ")
print("var_f0:", var_f0)
print("var_f1:", var_f1)
func2()
print("after func2: ")
print("var_f0:", var_f0)
print("var_f1:", var_f1)
func1()
输出:
before func2:
var_f0: 123
var_f1: 456
in func2 start......
var_f0: 123
Traceback (most recent call last):
File "U:/Project/Python_Training/Pytho_Basic/zz_test.py", line 29, in <module>
func1()
File "U:/Project/Python_Training/Pytho_Basic/zz_test.py", line 24, in func1
func2()
File "U:/Project/Python_Training/Pytho_Basic/zz_test.py", line 15, in func2
print("var_f1:", var_f1) # 在func2中可以访问
UnboundLocalError: local variable 'var_f1' referenced before assignment
用例3:在局部作用域中修正外部变量的方法用例1:在局部作用域中没有同名变量时,可以访问外部变量
# 全局变量,作用域:整个模块。
var_f0 = 123
def func1():
# 局部变量,作用域:func1
var_f1 = 456
def func2():
global var_f0 # 声明改变量为外部变量
nonlocal var_f1 # 声明改变量为外部变量
print("in func2 start......")
print("var_f0:", var_f0) # 在func2中可以访问
print("var_f1:", var_f1) # 在func2中可以访问
var_f0 = 789 # 在func2中修正
var_f1 = 789 # 在func2中修正
print("in func2 end......")
print("before func2: ")
print("var_f0:", var_f0)
print("var_f1:", var_f1)
func2()
print("after func2: ")
print("var_f0:", var_f0)
print("var_f1:", var_f1)
func1()
输出:
before func2:
var_f0: 123
var_f1: 456
in func2 start......
var_f0: 123
var_f1: 456
in func2 end......
after func2:
var_f0: 789
var_f1: 789