
3.2 变量和常量
变量用于引用在程序中可能会变化的值。本节将介绍Python中的变量和常量,以及Python中的关键字。
3.2.1 变量命名
在计算机程序中,需要处理大量带有数值的数据,回想在求解数学问题时,通常会选取合适的名字来表示这些量值。在程序中,若需要对两个或多个数据求和,则需要先把这些数据存储起来,然后再进行累加。在Python中,存储一个数据需要利用变量(Variable),示例如下。

在大多数编程语言中,这一过程被称为“把值存储在变量中”,即存储在计算机内存中的某个位置。事实上,往往只需记住存储变量时所用的名字,并直接调用这个名字即可,不需要知道这些信息被存储在内存中的具体位置。
注意在Python中,不需要先声明变量名及其类型,直接赋值即可创建各种类型的变量,因为Python会通过赋值给变量来自动判定数据类型。
Python中的变量指向存储在内存中某个值,可以理解为标签。变量应尽量选择描述性的名字(Descriptive Name)命名,而不是用像x和y这样的名字:如用radius作为半径值的变量,而用area作为面积值的变量。
变量命名由数字或字符的任意长度的字符串组成,必须以字母开头。在Python3中,汉字也可以出现在变量名中。Python对大小写敏感,虽然可以以大写字母命名,但对于变量名还是推荐使用小写字母。交互模式输入如下。

下画线“_”可以出现在变量名中,常用于连接多个词组,如i_agree_with,变量_2后面将会讲到以下画线开头的标识符具有特殊意义。
如果给变量取非法名称,解释器会提示语法错误,示例如下。

注意 因为Python区分大小写,所以number、Number和NUMBER是不同的标识符。
另外Python不允许使用关键字作为变量名,Python中共有33个关键字不能作为变量名使用。同时,Python中的关键字是区分大小写的,表3-2列举了Python中的关键字。
表3-2 Python中的关键字

提示 描述性标识符可以使程序阅读性更强。尽量避免使用简写的标识符,完整的单词更具描述性,例如:numberOfStudents比numStuds、numOfStuds或numOfStudents更好。本书完整的程序中使用描述性的变量名。然而,也会偶尔为了简洁起见在代码段中使用像i、j、k、x和y这样的名字。在易于理解的前提下,这些简洁的名字也为代码段提供了一种风格。
3.2.2 变量赋值
赋值语句将一个值指定给一个变量,在Python中赋值语句可以作为一个表达式,将等号“=”作为赋值操作符(Assignment Operator)。赋值语句语法如下所示。

表达式(Expression)表示涉及值、变量和操作符的一个运算,它们组合在一起表达一个新值。并且,表达式只有在赋值语句中才会计算得到结果。在Python中,没有显式变量声明,直接变量赋值即可。

若要给变量赋值,变量名必须在赋值操作符的左边。因此,下面语句有误。

3.2.3 局部变量
变量的作用域决定程序代码片段能否访问到该变量,若超出该区域,访问会出错。程序一般会根据变量定义时所在的位置,将其分为“全局变量”和“局部变量”。
局部变量(Local Variable)是指定义在函数体内并限定在当前函数内使用,而不能被其他函数直接访问的变量。不同的函数中,可以定义相同名字的局部变量,并且不会相互影响。
在图3-1中,可见局部变量从函数内被调用时被分配内存,函数调用结束后释放占用的内存空间。局部变量的使用既能提高内存利用率,也能提高变量数据的安全性。为了临时保存数据需要在函数中定义变量来进行存储,这就是局部变量的作用。

图3-1 局部变量的作用范围
代码清单3-4 局部变量


运行结果:

在代码清单3-4中,虽然两个函数都定义了相同的变量a,但是可以看出,在同一个函数体内,重新给局部变量赋值是会改变其值的。而在不同的函数体中,可以定义相同名字的局部变量,那么同名变量的作用域会被限定在这个函数体中。
提示 在函数外部使用函数内部定义的变量,就会抛出NameError异常。
3.2.4 全局变量
全局变量(Global Variable)是指在函数外部定义的变量。全局变量从被定义后就被分配内存,在定义位置之后的所有函数都能调用,直至源文件结束而释放内存。
全局变量与局部变量的本质区别在于作用域,全局变量的作用域是整个文件,局部变量的作用域是整个函数,但是不包括类似函数中的函数等其他作用域。在图3-2中可见,在Python中,全局变量在整个文件中定义,且在定义位置之后的全局范围内都可访问;局部变量在函数中定义,且只能在该函数中定义位置之后的范围内被调用。

图3-2 全局变量的作用范围
在Python中,若要在函数内部访问全局变量,则需要在函数内部使用global关键字声明函数内部同名变量指向全局变量;若要在内层函数中访问外层函数变量,则需要在内层函数中使用nonlocal关键字声明内层函数同名变量指向外层变量。global用于在函数内调用全局变量;nonlocal用于在函数或其他作用域中访问外层变量(不包含全局变量),其是Python 3.0新增关键字,在低于3.0的版本中不被支持。详细内容可见3.2.6节关键字部分。使用方法见代码清单3-5。
代码清单3-5 全局变量

运行结果:

使用global关键字修饰函数中的全局变量(第3行),可以在函数中访问全局变量(第4行),在函数内修改全局变量(第5行),但不影响函数体外被修改(第15行);使用nonlocal关键字修饰外层变量x后在内层函数中可以访问(8~10行),同样在内层函数中修改该值后外层的局部变量也随之改变(第11行)。
全局变量y在使用关键字global时可以被任意函数调用,而局部变量x只能在所在函数内被调用。如果变量x要在函数内的函数或其他作用域中被调用,则需要使用关键字nonlocal。当全局变量的值不会被函数内修改时,可以省略关键字global,这样局部作用域中的变量会覆盖全局作用域中的同名变量,此时只有局部作用域中的变量可被操作。在Python程序开发时,不建议函数内的局部变量和全局变量使用相同的变量名,也尽量少用全局变量。
3.2.5 常量
变量的值在程序执行的过程中可能会被改变,但是常量代表永远不会变的固定数据。与C/C++等编程语言不同,Python中没有表示常量的特殊语法,如const,但是在Python中有一些约定俗成的使用规范:为了区分常量和变量,全部使用大写字母来命名常量,并且在使用过程中不再更改,如PI、STATUS等。当然,对于自定义的常量,本质上值可以被修改,但一般不会。把它们当作常量来使用,是一种默认的编程习惯。
Python中有6个内置常量:True、False、None、NotImplemented、Ellipsis和__debug__,下面将介绍这6个常量的含义。
(1)True:表示真值的常量,bool类型,对它进行任何赋值操作都会出现语法错误。类型:

若对其赋值:

(2)False:表示假值的常量,bool类型,对它进行任何赋值操作都会出现语法错误。类型:

若对其赋值:

(3)None:一个特殊的常量,nonetype类型,不能和其他类型数据进行比较,可以将它赋值给任何对象,但不能对它进行赋值,如果函数没有return语句,则返回none。类型:

若对其赋值:

没有return语句的函数:

有return语句的函数:

(4)NotImplemented:一个真值常量,具有NotImplemented type类型。若对它重新赋值、甚至改变它的属性名称,编译器都不会报错,因此它不是一个绝对的常量。一般不会对它进行重新赋值,因为这有可能会影响程序的运行结果。
用bool测试常量值:

类型:

若对其赋值:

(5)Ellipsis:一个真值常量,ellipsis类型,与NotImplemented类似,对它重新赋值,编译器不会报错,因此它不是一个绝对的常量。一般不会对它进行重新赋值,因为这有可能会影响程序的运行结果。
用bool测试常量值:

类型:

若对其赋值:

(6)__debug__:bool类型值。若Python没有使用-O选项启动,它是真值常量,否则,它是假值常量。对它进行任何赋值操作都会出现语法错误。
用bool测试常量值(没有使用-O选项启动):

类型:


若对其赋值:

提示 常量和变量一定要区分大小写!
3.2.6 关键字
关键字是预先保留的标识符,每个关键字都有特殊含义。编程语言众多,但每种语言都有相应的关键字,Python也不例外。Python自带了一个keyword模块,用于检测关键字。
可通过导入keyword模块,执行keyword.kwlist命令获取关键字列表。

Python共有33个关键字,表3-3列举了不同关键字及其含义。
表3-3 Python关键字及其含义

(续)
