Python3基础篇(九)——命名空间和作用域
Python3基础篇(九)——命名空间和作用域
前言
阅读这篇文章我能学到什么?
这篇文章将使你弄明白Python3的命名空间和作用域到底意味着什么。
1 命名空间
命名空间的主要作用是为了防止命名冲突。各个命名空间是独立的,不同命名空间可以具有相同的命名,但同一个命名空间内不得重名(即使变量和函数之间也不能重名)。
1.1 命名空间分类
Python3有三类命名空间:
- 内置命名空间:Python3的内置名称(关键字、内置变量名、内置函数名)。
- 全局命名空间:在函数外及类外定义。
- 局部命名空间:在函数或类中定义的。
1.2 命名空间的查找顺序
当访问一个变量或函数时,python根据名称在命名空间中进行查找,但是几种命名空间查找顺序不同。查找顺序优先级为: 局部命名空间>全局命名空间>内置命名空间 。
这也就能理解当函数内局部变量和外部
代码示例:
1 | Parameter1 = 1 |
运行结果:
1 | 5 |
函数内变量与全局变量同名时,在函数内部访问的是局部变量,重载内置函数时访问的是重载后的函数。理解了命名空间的优先访问顺序,也就容易理解重载了。
2 作用域
作用域是Python3程序可以直接访问命名空间的正文区域(作用于是用命名空间的概念来定义的,它强调代码)。类似命名空间,Python3访问一个变量或函数会从内到外依次访问所有的作用域。变量或函数的作用域取决于变量或函数的定义位置,变量或函数作用域确定后,哪些地方具有对其访问的权限也就确定了。
2.1 作用域分类
Python3的作用域有四种:
- 局部作用域:为最内层作用域,为函数内部。
- 嵌套作用域:即非局部也非全局的作用域。当函数(或类)里面又嵌套定义了函数时,对于内层函数来说,外层就是nonlocal。
- 全局作用域:脚本的最外层。
- 内建作用域:包含内建的变量、函数、关键字。
2.2 作用域的查找顺序
查找的顺序优先级为: 内部作用域>嵌套作用域>全局作用域>内建作用域 。
代码示例:
1 | Parameter1 = 1 #全局作用域 |
运行结果:
1 | 2 |
Python3查找变量或函数时按照优先级进行查找(最先查找局部作用域,最后查找内建作用域),但是不能反过来,比如不能在全局作用域查到位于局部作用域的变量。理解了Python3作用域访问的优先级就能理解“外部不能访问内部变量或函数”。
在Python3里能引入新作用域的只有三种: 函数、类、模块 而其他代码块如:if/elif/else、for/while、try/except等不会引入新的作用域,因此外部可以直接访问到这些代码块内的变量。这点与c/c++有很大差异。
代码示例:
1 | if True: |
运行结果:
1 | 1 |
2.3 global和nonlocal关键字
外部作用域无法访问内部作用域内的变量或函数这点不能改变(比如全局作用域不能访问到函数内的局部作用域内的变量),但是当内部作用域里想修改外部作用域变量值或访问外部函数时需要借助关键字global
和nonlocal
。
2.3.1 global
通过global
声明全局变量或全局函数,使得内部作用域可修改全局变量的值或访问到全局函数。
2.3.1.1 global声明全局变量
前面讲作用域的时候代码示例里演示了在函数内部访问(指读取值)了全局变量,若想在局部作用域修改全局变量的值则需要通过global
声明全局变量。
代码示例:
1 | Parameter = 1 |
运行结果:
1 | 1 |
需要注意的是如果内部作用域定义了和外部作用域同名的变量后再声明外部这个全局变量会报错。
2.3.1.2 global声明全局函数
类似声明全局变量的用法,global
也能声明全局函数。
代码示例:
1 | def Function1(): #定义全局函数 |
运行结果:
1 | 1 |
2.3.2 nonlocal
类似global
,想要修改嵌套作用域的变量或访问嵌套作用域的函数,则需要使用nonlocal
进行声明。
2.3.2.1 nonlocal声明嵌套变量
在嵌套定义的函数内可以读取到外层函数定义的变量值,但是若要修改外层函数变量的值则需要使用nonlocal
进行声明变量。
代码示例:
1 | Parameter = 1 #全局作用域变量 |
运行结果:
1 | 3 |
2.3.2.2 nonlocal声明嵌套函数
类似声明嵌套变量的用法,nonlocal
也能声明嵌套函数。
代码示例:
1 | def Function1(): #全局函数 |
运行结果:
1 | In Function1 |