2.2 Python中的变量和参数
2.2.1 局部变量和全局变量
Python中的变量可以是局部变量也可以是全局变量。变量在以下情况时,是一个函数的局部变量:
- 作为函数的形参。
- 出现在函数中声明语句的左边。
- 限定在控制结构内部(如
for
、with
和except
)。
当一个非局部的变量(在之前的代码中出现)在函数内被引用,那么它是一个非局部变量。你可以按如下所示指定一个非局部变量:
一个变量可以显式地声明为全局变量,如下所示:
下面的代码块对照演示了局部变量和全局变量的不同表现:
上述代码块的输出如下所示:
2.2.2 变量的作用域
Python变量的可访问性或作用域取决于变量的定义位置。Python提供两种作用域:全局作用域和局部作用域。全局变量实际上是模块级别的作用域(即当前文件),因此你可以在不同的文件中使用相同的名称定义变量,它们会被当作不同的变量对待。
局部变量很简单:它们是在函数内定义的变量,并且只能在定义它们的函数内被访问。任何非局部的变量都具有全局作用域,这些变量只对定义它的文件是“全局的”,并且可以在文件中的任何地方访问它们。
下面看两个关于变量的场景。首先,假设有两个文件(即模块)file1.py
和file2.py
都包含一个叫作x
的变量,同时file1.py
导入了file2.py
。现在的问题是如何在这两个文件中区分变量x
。举个例子,假设file2.py
中包含下面两行代码:
假设file1.py
中包含如下代码:
在命令行中运行file1.py
,你会得到如下输出:
第二个场景涉及一段包含两个变量的程序,一个是局部变量,一个是全局变量,两个变量具有相同的命名。根据前面的规则,在定义变量的函数内使用的是局部变量,而在函数外会使用全局变量。
下面的代码说明了具有相同变量名的局部变量和全局变量的用法:
当执行上述代码的时候,将得到以下结果:
对于不确定作用域的变量,在使用变量x
时不带模块前缀会怎么样?答案取决于Python执行的以下一系列步骤:
1)在局部作用域中检查该名称的变量。
2)扩大检查的封闭作用域,并检查该名称的变量。
3)执行第2步直到检查全局作用域(即模块级别)。
4)如果仍未找到x
,则检查Python的__builtins__
(内建模块)。
注意:你可以通过调用locals()
和globals()
来访问Python用于跟踪局部变量和全局变量的字典。
2.2.3 引用传递和值传递
Python中的所有参数(形参和实参)都是引用传递。因此,当你在一个函数内修改了其形参引用的时候,这个改变会反映在其调用函数中。例如:
这里我们持有对传递对象的引用,并对其添加值。它的结果如下所示:
引用传递这一事实引出了可变性与不可变性的概念,我们将在第3章讨论。
2.2.4 实参和形参
Python区分函数调用时的实参和函数声明时的形参:位置(强约束)和关键字(可选/默认值)。这个概念很重要,因为Python有用于包装和拆包这类参数的运算符。
Python从迭代器中拆包位置参数,如下所示: