语言元素
变量和类型
在程序设计中,变量是一种存储数据的载体。计算机中的变量是实际存在的数据或者说是存储器中存储数据的一块内存空间,变量的值可以被读取和修改,这是所有计算和控制的基础。计算机能处理的数据有很多种类型,除了数值之外还可以处理文本、图形、音频、视频等各种各样的数据,那么不同的数据就需要定义不同的存储类型。Python中的数据类型很多,而且也允许我们自定义新的数据类型(这一点在后面会讲到),我们先介绍几种常用的数据类型。
- 整型:Python中可以处理任意大小的整数(Python 2.x中有
int和long两种类型的整数,但这种区分对Python来说意义不大,因此在Python 3.x中整数只有int这一种了),而且支持二进制(0b/0B开头;如0b100,换算成十进制是4)、八进制(0o/0O开头;如0o100,换算成十进制是64)、十进制(100)和十六进制(0x/0X开头;0x100,换算成十进制是256)的表示法。 - 浮点型:浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,浮点数除了数学写法(如
123.456)之外还支持科学计数法(如1.23456e2)。 - 字符串型:字符串是以单引号或双引号括起来的任意文本,比如
'hello'和"hello",字符串还有原始字符串表示法、字节字符串表示法、Unicode字符串表示法,而且可以书写成多行的形式(用三个单引号或三个双引号开头,三个单引号或三个双引号结尾)。 - 布尔型:布尔值只有
True、False两种值,要么是True,要么是False,在Python中,可以直接用True、False表示布尔值(请注意大小写),也可以通过布尔运算计算出来(例如3 < 5会产生布尔值True,而2 == 1会产生布尔值False)。 - 复数型:形如
3+5j,跟数学上的复数表示一样,唯一不同的是虚部的i换成了j。实际上,这个类型并不常用,大家了解一下就可以了。
变量命名
对于每个变量我们需要给它取一个名字,就如同我们每个人都有属于自己的响亮的名字一样。在Python中,变量命名需要遵循以下这些必须遵守硬性规则和强烈建议遵守的非硬性规则。
- 硬性规则:
- 变量名由字母(广义的Unicode字符,不包括特殊字符)、数字和下划线构成,数字不能开头。
- 大小写敏感(大写的
a和小写的A是两个不同的变量)。 - 不要跟关键字(有特殊含义的单词,后面会讲到)和系统保留字(如函数、模块等的名字)冲突。
- PEP 8要求:
- 用小写字母拼写,多个单词用下划线连接。
- 受保护的实例属性用单个下划线开头(后面会讲到)。
- 私有的实例属性用两个下划线开头(后面会讲到)。
当然,作为一个专业的程序员,给变量(事实上应该是所有的标识符)命名时做到见名知意也是非常重要的。
在Python中可以使用type函数对变量的类型进行检查。程序设计中函数的概念跟数学上函数的概念是一致的,数学上的函数相信大家并不陌生,它包括了函数名、自变量和因变量。如果暂时不理解这个概念也不要紧,我们会在后续的章节中专门讲解函数的定义和使用。
1 | |
可以使用Python中内置的函数对变量类型进行转换。
int():将一个数值或字符串转换成整数,可以指定进制。float():将一个字符串转换成浮点数。str():将指定的对象转换成字符串形式,可以指定编码。chr():将整数转换成该编码对应的字符串(一个字符)。ord():将字符串(一个字符)转换成对应的编码(整数)。
下面的代码通过键盘输入两个整数来实现对两个整数的算术运算。
1 | |
说明:上面的print函数中输出的字符串使用了占位符语法,其中
%d是整数的占位符,%f是小数的占位符,%%表示百分号(因为百分号代表了占位符,所以带占位符的字符串中要表示百分号必须写成%%),字符串之后的%后面跟的变量值会替换掉占位符然后输出到终端中,运行上面的程序,看看程序执行结果就明白啦。
Python变量定义时无须指定变量类型(动态语言),Java需要定义变量类型(静态语言);
可以把一个变量a赋值给另一个变量b,这个操作实际上是把变量b指向变量a所指向的数据,例如下面的代码:
1 | |
运算符
Python支持多种运算符,下表大致按照优先级从高到低的顺序列出了所有的运算符,运算符的优先级指的是多个运算符同时出现时,先做什么运算然后再做什么运算。除了我们之前已经用过的赋值运算符和算术运算符,我们稍后会陆续讲到其他运算符的使用。
| 运算符 | 描述 |
|---|---|
[] [:] |
下标,切片 |
** |
指数 |
~ + - |
按位取反, 正负号 |
* / % // |
乘,除,模,整除 |
+ - |
加,减 |
>> << |
右移,左移 |
& |
按位与 |
^ | |
按位异或,按位或 |
<= < > >= |
小于等于,小于,大于,大于等于 |
== != |
等于,不等于 |
is is not |
身份运算符 |
in not in |
成员运算符 |
not or and |
逻辑运算符 |
= += -= *= /= %= //= **= &= ` |
= ^= >>= <<=` |
说明: 在实际开发中,如果搞不清楚运算符的优先级,可以使用括号来确保运算的执行顺序。
赋值运算符
赋值运算符应该是最为常见的运算符,它的作用是将右边的值赋给左边的变量。下面的例子演示了赋值运算符和复合赋值运算符的使用。
1 | |
比较运算符和逻辑运算符
比较运算符有的地方也称为关系运算符,包括==、!=、<、>、<=、>=,我相信没有什么好解释的,大家一看就能懂,唯一需要提醒的是比较相等用的是==,请注意这个地方是两个等号,因为=是赋值运算符,我们在上面刚刚讲到过,==才是比较相等的比较运算符。比较运算符会产生布尔值,要么是True要么是False。
逻辑运算符有三个,分别是and、or和not。and字面意思是“而且”,所以and运算符会连接两个布尔值,如果两个布尔值都是True,那么运算的结果就是True;左右两边的布尔值有一个是False,最终的运算结果就是False。相信大家已经想到了,如果and左边的布尔值是False,不管右边的布尔值是什么,最终的结果都是False,所以在做运算的时候右边的值会被跳过(短路处理),这也就意味着在and运算符左边为False的情况下,右边的表达式根本不会执行。or字面意思是“或者”,所以or运算符也会连接两个布尔值,如果两个布尔值有任意一个是True,那么最终的结果就是True。当然,or运算符也是有短路功能的,在它左边的布尔值为True的情况下,右边的表达式根本不会执行。not运算符的后面会跟上一个布尔值,它的作用是得到与该布尔值相反的值,也就是说,后面的布尔值如果是True运算结果就是False,而后面的布尔值如果是False则运算结果就是True。
1 | |
说明:比较运算符的优先级高于赋值运算符,所以
flag0 = 1 == 1先做1 == 1产生布尔值True,再将这个值赋值给变量flag0。,进行分隔,输出的内容之间默认以空格分开。
数值运算函数
| 函数 | 功能 |
|---|---|
| abs(x) | 绝对值,x的绝对值 abs(-10.01) 结果为 10.01 |
| divmod(x,y) | 商余,(x//y, x%y),同时输出商和余数;divmod(10, 3) 结果为 (3, 1) |
| pow(x, y[, z]) | 幂余,(x**y)%z,[..]表示参数z可省略;pow(3, pow(3, 99), 10000) 结果为 4587 |
| round(x[, d]) | 四舍五入,d是保留小数位数,默认值为0;round(-10.123, 2) 结果为 -10.12 |
if、elif和else
在Python中,要构造分支结构可以使用if、elif和else关键字。所谓关键字就是有特殊含义的单词,像if和else就是专门用于构造分支结构的关键字,很显然你不能够使用它作为变量名(事实上,用作其他的标识符也是不可以)。下面的例子中演示了如何构造一个分支结构。
1 | |
需要说明的是和C/C++、Java等语言不同,Python中没有用花括号来构造代码块而是使用了缩进的方式来表示代码的层次结构,如果if条件成立的情况下需要执行多条语句,只要保持多条语句具有相同的缩进就可以了。换句话说连续的代码如果又保持了相同的缩进那么它们属于同一个代码块,相当于是一个执行的整体。缩进可以使用任意数量的空格,但通常使用4个空格,建议大家不要使用制表键或者设置你的代码编辑工具自动将制表键变成4个空格。
1 | |
当然如果要构造出更多的分支,可以使用if...elif...else...结构或者嵌套的if...else...结构,下面的代码演示了如何利用多分支结构实现分段函数求值。
1 | |
当然根据实际开发的需要,分支结构是可以嵌套的,即在if的内部构造出一个新的分支结构,同理elif和else中也可以再构造新的分支,我们称之为嵌套的分支结构,也就是说上面的代码也可以写成下面的样子。
1 | |
说明: 大家可以自己感受一下这两种写法到底是哪一种更好。在之前我们提到的Python之禅中有这么一句话“Flat is better than nested.”,之所以提倡代码“扁平化”是因为嵌套结构的嵌套层次多了之后会严重的影响代码的可读性,所以能使用扁平化的结构时就不要使用嵌套。
for-in循环
如果明确的知道循环执行的次数或者要对一个容器进行迭代(后面会讲到),那么我们推荐使用for-in循环,例如下面代码中计算1~100求和的结果($\displaystyle \sum \limits_{n=1}^{100}n$)。
1 | |
需要说明的是上面代码中的range(1, 101)可以用来构造一个从1到100的范围,当我们把这样一个范围放到for-in循环中,就可以通过前面的循环变量x依次取出从1到100的整数。当然,range的用法非常灵活,下面给出了一个例子:
range(101):可以用来产生0到100范围的整数,需要注意的是取不到101。range(1, 101):可以用来产生1到100范围的整数,相当于前面是闭区间后面是开区间。range(1, 101, 2):可以用来产生1到100的奇数,其中2是步长,即每次数值递增的值。range(100, 0, -2):可以用来产生100到1的偶数,其中-2是步长,即每次数字递减的值。
知道了这一点,我们可以用下面的代码来实现1~100之间的偶数求和。
1 | |
当然,也可以通过在循环中使用分支结构的方式来实现相同的功能,代码如下所示。
1 | |
说明:相较于上面直接跳过奇数的做法,下面这种做法很明显并不是很好的选择。
while循环
如果要构造不知道具体循环次数的循环结构,我们推荐使用while循环。while循环通过一个能够产生或转换出bool值的表达式来控制循环,表达式的值为True则继续循环;表达式的值为False则结束循环。
下面我们通过一个“猜数字”的小游戏来看看如何使用while循环。猜数字游戏的规则是:计算机出一个1到100之间的随机数,玩家输入自己猜的数字,计算机给出对应的提示信息(大一点、小一点或猜对了),如果玩家猜中了数字,计算机提示用户一共猜了多少次,游戏结束,否则游戏继续。
1 | |
循环控制保留字
break跳出并结束当前整个循环(break仅跳出当前最内层循环),执行循环后的语句;
continue结束当次循环,继续执行后续次数循环;
break和continue可以与for和while循环搭配使用。
和分支结构一样,循环结构也是可以嵌套的,也就是说在循环中还可以构造循环结构。下面的例子演示了如何通过嵌套的循环来输出一个九九乘法表。
1 | |
迭代
如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:
1 | |
如果要对list实现类似Java那样的下标循环怎么办?
Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:
1 | |
input()
input() 是 Python 的内置函数,用于从控制台读取用户输入的内容。input() 函数总是以字符串的形式来处理用户输入的内容,所以用户输入的内容可以包含任何字符。
input() 函数的用法为:
1 | |
说明:
- str 表示一个字符串类型的变量,input 会将读取到的字符串放入 str 中。
- tipmsg 表示提示信息,它会显示在控制台上,告诉用户应该输入什么样的内容;如果不写 tipmsg,就不会有任何提示信息。
【实例】input() 函数的简单使用:
1 | |
运行结果示例:
1 | |
↙表示按下回车键,按下回车键后 input() 读取就结束了。
本例中我们输入了两个整数,希望计算出它们的和,但是事与愿违,Python 只是它们当成了字符串,+起到了拼接字符串的作用,而不是求和的作用。
我们可以使用 Python 内置函数将字符串转换成想要的类型,比如:
- int(string) 将字符串转换成 int 类型;
- float(string) 将字符串转换成 float 类型;
- bool(string) 将字符串转换成 bool 类型。
修改上面的代码,将用户输入的内容转换成数字:
1 | |
运行结果:
1 | |
print()
print() 函数的详细语法格式如下:
1 | |
从上面的语法格式可以看出,value 参数可以接受任意多个变量或值,因此 print() 函数完全可以输出多个值。例如如下代码:
1 | |
运行上面代码,可以看到如下输出结果:
1 | |
从输出结果来看,使用 print() 函数输出多个变量时,print() 函数默认以空格隔开多个变量,如果读者希望改变默认的分隔符,可通过 sep 参数进行设置。例如输出语句:
1 | |
运行上面代码,可以看到如下输出结果:
1 | |
在默认情况下,print() 函数输出之后总会换行,这是因为 print() 函数的 end 参数的默认值是“\n”,这个“\n”就代表了换行。如果希望 print() 函数输出之后不会换行,则重设 end 参数即可,例如如下代码:
1 | |
上面三条 print() 语句会执行三次输出,但由于它们都指定了 end=””,因此每条 print() 语句的输出都不会换行,依然位于同一行。运行上面代码,可以看到如下输出结果:
1 | |
file 参数指定 print() 函数的输出目标,file 参数的默认值为 sys.stdout,该默认值代表了系统标准输出,也就是屏幕,因此 print() 函数默认输出到屏幕。实际上,完全可以通过改变该参数让 print() 函数输出到特定文件中,例如如下代码:
1 | |
上面程序中,open() 函数用于打开 demo.txt 文件,接连 2 个 print 函数会将这 2 段字符串依次写入此文件,最后调用 close() 函数关闭文件。
print() 函数的 flush 参数用于控制输出缓存,该参数一般保持为 False 即可,这样可以获得较好的性能。
None
None是Python的空值类型。如果一个函数没有明确的返回值,就会默认返回None:
1 | |
None也常常作为函数的默认参数:
1 | |
另外,None不仅是一个保留字,还是唯一的NoneType的实例:
1 | |
日期和时间
Python内建的datetime模块提供了datetime、date和time类型。datetime类型结合了date和time,是最常使用的:
1 | |
根据datetime实例,你可以用date和time提取出各自的对象:
1 | |
strftime方法可以将datetime格式化为字符串:
1 | |
strptime可以将字符串转换成datetime对象:
1 | |

当你聚类或对时间序列进行分组,替换datetimes的time字段有时会很有用。例如,用0替换分和秒:
1 | |
因为datetime.datetime是不可变类型,上面的方法会产生新的对象。
两个datetime对象的差会产生一个datetime.timedelta类型:
1 | |
结果timedelta(17, 7179)指明了timedelta将17天、7179秒的编码方式。
将timedelta添加到datetime,会产生一个新的偏移datetime:
1 | |
pass
pass是Python中的非操作语句。代码块不需要任何动作时可以使用(作为未执行代码的占位符);因为Python需要使用空白字符划定代码块,所以需要pass:
1 | |
range
range函数返回一个迭代器,它产生一个均匀分布的整数序列:
1 | |
range的三个参数是(起点,终点,步进):
1 | |
可以看到,range产生的整数不包括终点。range的常见用法是用序号迭代序列:
1 | |
可以使用list来存储range在其他数据结构中生成的所有整数,默认的迭代器形式通常是你想要的。下面的代码对0到99999中3或5的倍数求和:
1 | |
虽然range可以产生任意大的数,但任意时刻耗用的内存却很小。
三元表达式
Python中的三元表达式可以将if-else语句放到一行里。语法如下:
1 | |
true-expr或false-expr可以是任何Python代码。它和下面的代码效果相同:
1 | |
下面是一个更具体的例子:
1 | |
和if-else一样,只有一个表达式会被执行。因此,三元表达式中的if和else可以包含大量的计算,但只有True的分支会被执行。
虽然使用三元表达式可以压缩代码,但会降低代码可读性。



