5. 基础:基本概念

只打印 hello world 肯定是不够的!你肯定希望做得比这还要多——比如输入一些内容,进行操作,然后得到输出。 在 Python 中我们可以通过使用变量与常量来实现这一目标,本章我们将会学习这些概念以及一些相关的概念。

5.1. 注释

注释 是任何存在于 # 号右侧的文字,它主要是写给程序员看的笔记说明。举个例子:

print('hello world') # 注意 print 是一个函数

或者:

# 注意 print 是一个函数
print('hello world')

你应该在程序中尽可能多地使用注释。注释可以用于:

  • 解释假设
  • 说明重要的决定
  • 解释重要的细节
  • 说明你想要解决的问题
  • 说明你想要在程序中克服的问题,等等。

代码会告诉你怎么做,注释会告诉你为何这么做。

写注释对读你的程序的人来说非常有用,因为他们可以相对容易地理解你的程序在做啥。请记住,这个人很可能是六个月后的你!

5.2. 字面常量

字面常量 (Literal Constants)是诸如 51.23 这样的数字,或者是 This is a string 这样的文本。

因为你用的就是它字面意义上的值或是内容。 例如数字 2 总是表示它本身——因为它的值不能被改变,所以是个常量。诸如此类都被称作 字面常量

5.3. 变量

常量一成不变是很无聊的,我们需要一些能够存储任何信息并且可操纵性强的量,这就是 变量 (Variables)。 正如它的名字一样,变量的值是可以变化的,也就是说,你可以用变量来存储任何东西。变量只是你的计算机内存中用以存储信息的一部分。 与 字面常量 不同,你需要通过一些方式来访问这些变量,因此你需要为它们命名。

命名需要遵守以下规则:

  • 第一个字符必须是字母表中的字母(大写 ASCII 字符或小写 ASCII 字符或 Unicode 字符)或下划线(_)。
  • 其它部分可以由字符(大写 ASCII 字符或小写 ASCII 字符或 Unicode 字符)、下划线(_)、数字(0~9)组成。
  • 名称区分大小写。例如,mynamemyName 并不等同。要注意到前者是小写字母 n 而后者是大写字母 N
  • 有效 的名称可以是 iname23,而 2thingsthis is spaced outmy-name>a1b2_c3 都是 无效 的名称。

在编程界有一些经典的命名规则:

  • 匈牙利命名法(Hungarian notation):通过在变量名前面加上相应的小写字母的符号标识作为前缀,标识出变量的作用域,类型等,如 nSizefPrice。这个写法比较紧凑,多用于需要声明数据类型的早期语言。
  • 驼峰命名法(Camel-Case):当变量名或函数名是由一个或多个单词连结在一起构成时,第一个单词以小写字母开始;从第二个单词开始以后的每个单词的首字母都采用大写字母,如:FirstNameLastName。不过当单词中包含全为大写字母的缩写时辨识度下降。
  • 下划线命名法(Under Score Case):与驼峰命名法类似,不过单词之间用下划线连接,如:First_name。这是 Python 程序员常用的命名法。

5.4. 数据类型

变量可以将各种形式的值保存为不同的 数据类型 (Data Type)。常用的数据类型包括下面几种:

数据类型 转换函数 示例 说明
布尔类型 bool() True , False  
数字 float() 123.143+4j  
字符串 str() 'hello', "I'm a BNUer"  
列表 list() [1,[2,'three'],'four'] 任意数据类型组成的有序集合
字典 dict () {'name':"zhang","age":18} 描述映射关系的无序集合
元组 tuple() (1,'spam',4,'K') 不可变的有序集合
集合 set() {'a','b','c'} 无序不重复元素集

我们将在后面的章节中依次介绍这些数据类型。

5.5. 布尔类型

布尔类型 (Boolean)是用于逻辑判断的特殊类型。这个类型仅包括有两个值 True(真)和 False(假)。

注意

Python 区分大小写,这两个值的首字母都必须大写,否则会被视为普通变量名。

Python 中的布尔运算符有下面几个:>(大于)、>=(大于等于)、<(小于)、<=(小于等于)、==(等于)、!=(不等于)以及 not(非)、or(或)、and(与),使用方法及效果可以参考下面的示例:

>>> 1<2<3
True
>>> 1==3
False
>>> not 1==3
True
>>> 1>2 or 2>1
True
>>> 1<2 and 2!=1
True

对于非布尔类型的数据,也可以用函数 bool() 将其转换为布尔类型, 示例如下:

>>> bool('')    # 空字符串为假
False
>>> bool('hello')  # 字符串为真
True
>>> bool(5)    # 非零数字为真
True
>>> bool(-1)   # 负数也为真
True
>>> bool(0)    # 数字 0 为假
False

布尔值在参与数学运算时,会被自动转换成 0 和 1 , 示例如下:

>>> (1>2) + (2>1) + (3>1)
2
>>> (1>2) * (2>1)
0

5.6. 数字

数字主要分为两种类型—— 整数(Integers)与 浮点数(Floats)。 此外,你也可以使用类似 3+4i 的形式表示复数,用 0b10 表示二进制数,用 0o11 表示八进制数,用 0xa6 表示十六进制数。

整数是 2 这样的数。浮点数(Floating Point Numbers,在英文中也会简写为 floats )的例子是 3.2352.3E-4。 其中,E 表示 10 的次幂,大小写均可。在这里,52.3E-4 表示 52.3 * 10^-4

注意

Python 中没有单独的长整数类型 long,整数类型 int 可以容纳任何大小的整数,例如你可以直接计算 2**100

5.6.1. 运算符

运算符(Operators)是进行某些操作,并且可以用诸如 + 等符号或特殊关键词加以表达的功能。 运算符需要一些数据来进行操作,这些数据就被称作 操作数(Operands)。

要记得你可以随时在解释器中对案例里的表达式进行求值。 例如要想测试表达式 2+3,可以使用交互式 Python 解释器:

>>> 2 + 3
5
>>> 3 * 5
15

下面是可用运算符的速览:

  • + (加)
    • 两个对象相加。
    • 3 + 5 则输出 8'a' + 'b' 则输出 'ab'
  • - (减)
    • 从一个数中减去另一个数,如果第一个操作数不存在,则假定为零。
    • -5.2 将输出一个负数, 50 - 24 输出 26
  • * (乘)
    • 给出两个数的乘积,或返回字符串重复指定次数后的结果。
    • 2 * 3 输出 6'la' * 3 输出 'lalala'
  • ** (乘方)
    • 返回 x 的 y 次方。
    • 3 ** 4 输出 81 (即 3 * 3 * 3 * 3 )。
  • / (除)
    • x 除以 y
    • 13 / 3 输出 4.333333333333333
  • // (整除)
    • x 除以 y 并对结果向下取整至最接近的整数。
    • 13 // 3 输出 4
    • -13 // 3 输出 -5
  • % (取模)
    • 返回除法运算后的余数。
    • 13 % 3 输出 1-25.5 % 2.25 输出 1.5

Python 也对 C 语言风格的二进制位运算提供了支持:

  • << (左移)
    • 将数字的位向左移动指定的位数。(每个数字在内存中以二进制数表示,即 0 和 1 )
    • 2 << 2 输出 82 用二进制数表示为 10
    • 向左移 2 位会得到 1000 这一结果,表示十进制中的 8
  • >> (右移)
    • 将数字的位向右移动指定的位数。
    • 11 >> 1 输出 5
    • 11 在二进制中表示为 1011 ,右移一位后输出 101 这一结果,表示十进制中的 5
  • & (按位与)
    • 对数字进行按位与操作。
    • 5 & 3 输出 1
  • | (按位或)
    • 对数字进行按位或操作。
    • 5 | 3 输出 7
  • ^ (按位异或)
    • 对数字进行按位异或操作。
    • 5 ^ 3 输出 6
  • ~ (按位取反)

5.6.2. 表达式

表达式中一种比较常见的操作是对一个变量进行一项数学运算并将运算得出的结果返回给这个变量,对于这类运算通常有如下的快捷表达方式:

a = 2
a = a * 3

同样也可写作:

a = 2
a *= 3

要注意到 变量 = 变量 运算 表达式 会演变成 变量 运算 = 表达式

案例(将其保存为 expression.py ):

length = 5
breadth = 2

area = length * breadth
print('Area is', area)
print('Perimeter is', 2 * (length + breadth))

在终端中运行代码得到输出:

$ python expression.py
Area is 10
Perimeter is 14

它是如何工作的

矩形的长度(Length)与宽度(Breadth)存储在以各自名称命名的变量中。我们使用它们并借助表达式来计算矩形的面积(Area)与周长(Perimeter)。 我们将表达式 length * breadth 的结果存储在变量 area 中并将其通过使用 print 函数打印出来。 在第二种情况中,我们直接在 print 函数中使用了表达式 2 * (length + breadth) 的值。

同时,你需要注意到 Python 非常漂亮地打印出了我们想要的结果。 尽管我们没有特别在 Area is 和变量 area 之间指定空格,Python 依然会帮我们加上。 所以我们得到了一个整洁的输出结果,同时程序也因为这样的处理方式而变得更加易读(因为我们不需要在用在输出的时候考虑空格问题)。

5.6.3. 求值顺序

如果你有一个诸如 2 + 3 * 4 的表达式,是优先完成加法还是优先完成乘法呢? 上过小学二年级的都知道乘法运算符的优先级要高于加法运算符,应该先完成乘法。

下面将给出 Python 中从最低优先级(最少绑定)到最高优先级(最多绑定)的优先级表。 这意味着,在给定的表达式中,Python 将优先计算表中位列于后的较高优先级的运算符与表达式。

为了保持完整,下表直接从 Python 参考手册 中引用而来。 你最好使用圆括号操作符来对运算符与操作数进行分组,以更加明确地指定优先级。这也能使得程序可读性更好。

  • lambda:Lambda 表达式
  • if - else:条件表达式
  • or:布尔 “或”
  • and:布尔 “与”
  • not x:布尔 “非”
  • innot inisis not<<=>>=!===:比较,包括成员资格测试(Membership Tests)和身份测试(Identity Tests)
  • |:按位或
  • ^:按位异或
  • &:按位与
  • <<>>:移动
  • +-:加与减
  • *///%:乘、除、整除、取余
  • +x-x~x:正、负、按位取反
  • **:求幂
  • x[index]x[index:index]x(arguments...)x.attribute:下标、切片、调用、属性引用
  • (expressions...)[expressions...]{key: value...}{expressions...}:表示绑定或元组、表示列表、表示字典、表示集合

我们还没有遇到的运算符将在后面的章节中加以解释。

在上表中位列同一行的运算符具有相同优先级,例如 +- 就具有相同的优先级。 而具有相同优先级的运算符将从左至右的方式依次进行求值,如 2 + 3 + 4 将会以 (2 + 3) +4 的形式加以计算。

为了使表达式更加易读,我们可以使用括号。举个例子, 2 + (3 * 4) 要比 2 + 3 * 4 更加容易理解,因为后者还要求你了解运算符的优先级。 不过,使用括号同样也要适度,不要像 (2 + (3 * 4)) 这样冗余。

使用括号还有一个额外的优点——它能帮助我们改变运算的顺序。 同样举个例子,如果你希望在表达式中计算乘法之前应先计算加法,那么你可以将表达式写作 (2 + 3) * 4

5.6.4. 基础数学函数

Python 中也包含了一些基础的数学函数:

  • abs(x) 求绝对值
  • int(x) 取整数部分
  • round(x) 四舍五入取整
  • pow(x, y) x 的 y 次方
  • bin(x) 将整数 x 转换为二进制数
  • oct(x) 将整数 x 转换为八进制数
  • hex(x) 将整数 x 转换为十六进制数
  • complex(x,y) 生成复数类型 x+yj
  • eval() 表达式求值,用法如下:
>>> x = 1
>>> eval('x+1')
2

5.7. 字符串

一串 字符串 (String)是 字符 (Characters)的 序列 (Sequence)。 而字符包括所有的数字、符号、大小写字母、空格、制表符甚至回车。

你几乎会在所有的 Python 程序中使用字符串,所以请特别留意下面这部分内容!

5.7.1. 单引号

你可以使用单引号来指定字符串,例如 'Quote me on this'

所有引号内的空间,诸如空格与制表符,都将按原样保留。

5.7.2. 双引号

被双引号包括的字符串和被单引号括起的字符串其工作机制完全相同,此外它可以包括单引号,例如 "What's your name?"

5.7.3. 三引号

可以使用三个引号—— """''' 来表示多行注释。你可以在三引号之间自由地使用单引号与双引号,来看看这个例子:

'''This is a multi-line string. This is the first line.
This is the second line.
"What's your name?," I asked.
He said "Bond, James Bond."
'''

5.7.4. 操作字符串

在 Python 中,字符串支持部分运算符操作,这非常方便,例如:

>>> text = 'hello '
>>> text + 'world'
hello world
>>> text * 2
hello hello
>>> text > "b"    # 按位比较排序位置
True

字符串的内容也可以灵活地切片提取

>>> len(text)  # 获取字符串的总长度
5
>>> text[0]   # 索引从 0 开始
'h'
>>> text[-1]  # 索引也可以从最后一位开始
'o'
>>> text[1:4] # 冒号表示范围,1 为起始位置,4 为结束位置,左闭右开
'ell'

虽然我们可以轻松获取字符串中的部分内容,但字符串作为一个整体是不可改变的。 如果你试图更改其中的部分内容,将会得到类似下面的错误提示:

>>> text[1] = "b"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

5.7.5. 格式化方法

有时候我们会想要从其他信息中构建字符串,这正是 format() 方法大有用武之地的地方。

将以下内容保存为文件 str_format.py

age = 20
name = 'Swaroop'

print('{0} was {1} years old when he wrote this book'.format(name, age))
print('Why is {0} playing with that python?'.format(name))

输出:

$ python str_format.py
Swaroop was 20 years old when he wrote this book
Why is Swaroop playing with that python?

它是如何工作的

一个字符串可以使用某些特定的格式(Specification),随后, format 方法将被调用,使用这一方法中与之相应的参数替换这些格式。

在这里要注意我们第一次应用这一方法的地方,此处 {0} 对应的是变量 name ,它是该格式化方法中的第一个参数。 与之类似,第二个格式 {1} 对应的是变量 age ,它是格式化方法中的第二个参数。 请注意,Python 从 0 开始计数,这意味着索引中的第一位是 0 ,第二位是 1 ,以此类推。

我们可以通过联立字符串来达到相同的效果:

name + 'is' + str(age) + 'years old'

但这样实现不是很优雅,而且也容易出错。 如果用 format 的方法,转换至字符串的工作将由 format 方法自动完成,用不着这么繁琐。 并且当使用 format 方法时,我们可以直接改动文字而不必与变量打交道。

注意 {} 里的数字只是一个可选选项,你也可以写成:

age = 20
name = 'Swaroop'

print('{} was {} years old when he wrote this book'.format(name, age))
print('Why is {} playing with that python?'.format(name))

这样做同样能得到与前面的程序一样的输出结果。

另外,你可以用 int('12') 把一个可以读成整数的字符串转换为数字,但是其他类型的字符串不行。

Python 中 format 方法所做的事情是将每个参数值替换至格式所在的位置。 语法是 格式字符串.format(变量) ,格式字符串需要大括号括住。其中可以包含更详细的格式设定,例如:

# 对于浮点数 '0.333' 保留小数点 (.) 后三位
>>>print('{0:.3f}'.format(1.0/3))
0.333

# 对于整数 '3' ,强制带符号保留小数点后两位
>>>print('{:+.2f}'.format(3))
+3.00

# 对于浮点数,四舍五入取整输出
>>>print('{:.0f}'.format(2.71828))
3

# 将数字以百分比格式输出
>>>print('{:.2%}'.format(0.25))
25.00%

# 将数字以指数记法输出
>>>print('{:.2e}'.format(1000000000))
1.00e+09

# 使用下划线填充文本,并保持文字处于中间位置
# 使用 (^) 定义 '___hello___' 字符串长度为 11
print('{0:_^11}'.format('hello'))
___hello___

# 输出数字靠右对齐(默认),并指定宽度为 10
print('{:>10d}'.format(13))
           13

# 输出靠右对齐,左侧补零 (填充左边, 宽度为 2 )
print('{:0>2d}'.format(5))
05

# 基于关键词输出 'Swaroop wrote A Byte of Python'
print('{name} wrote {book}'.format(name='Swaroop', book='A Byte of Python'))
Swaroop wrote A Byte of Python

有必要注意的是 print 总是会以一个不可见的 “新一行” 字符(\n)结尾,因此重复调用 print 将会在相互独立的行中分别打印。 为防止打印过程中出现这一换行符,你可以通过 end 指定其应以空白结尾:

>>> print(1); print(2)
1
2
>>>print('a', end=''); print('b', end='')
ab

或者你通过 end 指定以空格结尾:

print('a', end=' '); print('b', end=' '); print('c')
a b c

5.7.6. 转义序列

想象一下,如果你希望生成一串包含单引号(')的字符串,你应该如何指定这串字符串? 例如,如果你想要的字符串是 "What's your name?"。 你不能用 'What's your name?',因为 Python 不知道哪里是字符串的开始、结束的地方。 所以,你必须指定这个单引号不代表这串字符串的结尾。这可以通过 转义序列 (Escape Sequence)来实现。 你通过 \ 来指定单引号(注意它是反斜杠,不是 /),像这样 'What\'s your name?'

另一种指定这一特别的字符串的方式是这样的:"What's your name?",如这个例子一般使用双引号。 类似地,你必须在使用双引号括起的字符串中对字符串内的双引号使用转义序列。 同样,你必须使用转义序列 \\ 来指定反斜杠本身。

如果你想指定一串双行字符串该怎么办? 一种方式即使用如前所述的三引号字符串,或者你可以使用一个表示新一行的转义序列—— \n 来表示新一行的开始。 下面是一个例子:

'This is the first line\nThis is the second line'

另一个你应该知道的大有用处的转义序列是制表符:\t。实际上还有很多的转义序列,这里只是最常用的几个。

有一件事情需要注意,在一个字符串中,一个放置在末尾的反斜杠表示字符串将在下一行继续,但不会添加新的一行。 例如:

"This is the first sentence. \
This is the second sentence."

相当于

"This is the first sentence. This is the second sentence."

5.7.7. 原始字符串

如果你需要指定一些未经过特殊处理的字符串,比如转义序列,那么你需要在字符串前增加 rR 来指定一个原始(Raw)字符串。下面是一个例子:

r"Newlines are indicated by \n"

针对正则表达式用户的提示

在处理正则表达式时应全程使用原始字符串,否则将会有大量 Backwhacking 需要处理。 例如,反向引用可以通过 '\\1'r'\1' 来实现。

5.7.8. 字符串方法

与我们之前见到的如 bool()print() 等通用函数不同,有些函数是字符串专用的。 这类属于特定数据类型的函数叫做 方法 (Method),它们是以 常量/变量.method() 的形式来使用的。 例如 upper 方法可以把字符串的的字母全部转为大写, lower 方法与之相反,示例如下:

>>> cn="China"
>>> cn.upper()
"CHINA"
>>> cn.lower()
'china'
>>> cn     # 注意字符串本身并没有变化
'China'

方法不仅适用与变量,也适用于常量。 .isalpha() / isdigit() / .isalnum() 是三个检测字符串中是否包含字母和数字的方法,示例如下:

>>> "abc".isalpha()
True
>>> "1234".isdigit()
True
>>> "123abc".isalnum()
Ture
>>> "1.23".isdigit()
False

不仅如此,只要方法返回的结果还是同样的数据类型,就可以进行接力。我们以替换字符的 .replace() 为例:

>>> a="abcdabc"
>>> a.replace('a' ,'b')
'bbcdbbc'
>>> a.replace('a' ,'b').replace('b' ,'c')
'cccdccc'

对于特定数据类型所支持的方法可以通过 dir() 函数查看,具体方法的语法和功能则可以通过 help() 函数查看。 在帮助文档界面中,可用方向键上下翻页,以 q 键退出。

>>> a="abcdabc"
>>> dir(a)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__',
'__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find',
'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit',
'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper',
'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex',
'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip',
'swapcase', 'title', 'translate', 'upper', 'zfill']
>>> help(a.find)

5.8. 如何编写 Python 程序

从今以后,保存和运行 Python 程序的标准步骤如下:

5.8.1. 使用编辑器

  1. 打开你选择的编辑器。
  2. 输入案例中给出的代码。
  3. 以给定的文件名将其保存成文件。
  4. 在终端中切换到程序文件所在目录,通过命令 python program.py 运行程序。

注意

运行程序时的输出要求与解释器中不同。在解释器环境中,所有函数和方法的返回值都会显示在终端中;而在程序中,只有 print 函数的结果会显示在屏幕上。

5.8.2. 使用 IDE

以 PyCharm 为例

  1. 打开 PyCharm 。
  2. 以给定的文件名创建新文件。
  3. 输入案例中给出的代码。
  4. 右键并运行当前文件。

注意

每当你需要提供命令行参数(Command Line Arguments)时,点击 Run -> Edit Configurations 并在 Script parameters: 部分输入相应参数,并点击 OK 按钮:

image0

5.8.3. Python 程序示例

输入并运行以下程序:

# 文件名:var.py
i = 5
print(i)
i = i + 1
print(i)

s = '''This is a multi-line string.
This is the second line.'''
print(s)

输出:

5
6
This is a multi-line string.
This is the second line.

它是如何工作的

下面是这一程序的工作原理。 首先,我们使用赋值运算符(=)将字面常量数值 5 赋值给变量 i 。 这一行被称之为 声明语句(Statement)因为其工作正是声明一些在这一情况下应当完成的事情:我们将变量名 i 与值 5 相连接。 然后,我们通过 print 语句来打印变量 i 所声明的内容,这一步只是将变量的值打印到屏幕上。

接着,我们将 1 加到 i 变量所存储的值中,并将得出的结果重新存储进这一变量。 然后我们将这一变量打印出来,得到的值应为 6

类似地,我们将字面文本赋值给变量 s ,并将其打印出来。

针对静态编程语言程序员的提示

变量只需被赋予某一值,不需要声明或定义数据类型。

5.9. 逻辑行与物理行

所谓 物理行(Physical Line)是你在编写程序时你所看到的内容。 所谓 逻辑行(Logical Line)是 Python 所看到的单个语句,Python 会假定每一个物理行会对应一个逻辑行。

逻辑行是诸如 print('hello world') 这样的一句语句——如果其本身是一行(正如你在编辑器里所看到的那样),那么它也对应着一行物理行。

Python 暗含这样一种期望:Python 鼓励程序员每一行使用一句独立语句从而使得代码更加可读。

如果你希望在一行物理行中指定多行逻辑行,那么你必须通过使用分号(;)来明确表明逻辑行或语句的结束。 下面是一个例子:

i = 5
print(i)

实际上等同于

i = 5;
print(i);

也等同于

i = 5; print(i);

也与这一写法相同

i = 5; print(i)

然而,我强烈建议你对于每一行物理行最多只写入一行逻辑行,这个观点就是说你不应该使用分号。 因为实际上,我 从未 在 Python 程序中使用、甚至是见过一个分号。

在一类情况下这一方法会颇为有用:如果你有一行非常长的代码,你可以通过使用反斜杠将其拆分成多个物理行。 这被称作 显式行连接(Explicit Line Joining):

s = 'This is a string. \
This continues the string.'
print(s)

输出:

This is a string. This continues the string.

类似地,

i = \
5

等同于

i = 5

在某些情况下,会存在一个隐含的假设,允许你不使用反斜杠。 这一情况即逻辑行以括号开始,它可以是方括号或花括号,但不能是右括号。这被称作 隐式行连接(Implicit Line Joining)。 你可以在后面当我们讨论核心:数据结构的章节时了解这一点。

5.10. 缩进

空白区在 Python 中十分重要。 实际上,空白区在各行的开头非常重要,这被称作 缩进(Indentation)。 在逻辑行的开头留下空白区(使用空格或制表符)用以确定各逻辑行的缩进级别,而后者又可用于确定语句的分组。

这意味着放置在一起的语句必须拥有相同的缩进,每一组这样的语句被称为 (block)。 我们将会在后面章节的案例中了解块这一概念是多么重要。

有一件事你需要记住:错误的缩进可能会导致错误。下面是一个例子:

i = 5
# 下面这一行将发生错误,注意行首有一个空格
 print('Value is', i)
print('I repeat, the value is', i)

当你运行这一程序时,你将得到如下错误:

  File "whitespace.py", line 3
    print('Value is', i)
    ^
IndentationError: unexpected indent
# 缩进错误:意外缩进

你会注意到第二行开头有一个空格。Python 指出的错误信息告诉我们这个程序的语法是无效的,意即,程序没有被正确地写入。 这一信息对你的意义是 你不能任意开始一个新的语句块(当然,除非你一直在使用默认的主代码块)。 你可以使用新块的情况将在核心:控制流等章节加以介绍。

如何缩进

使用四个空格来缩进。这是来自 Python 语言官方的建议。好的编辑器会自动为你完成这一工作。 请确保你在缩进中使用数量一致的空格,否则你的程序将不会运行,或引发不期望的行为。

针对静态编程语言程序员的提示

Python 将始终对块使用缩进,并且绝不会使用大括号。 你可以通过运行 from __future__ import braces 来了解更多信息。

5.11. 总结

现在我们已经了解了诸多本质性的细节,我们可以前去了解控制流语句等更多更加有趣的东西。记得一定要充分理解你在本章所阅读的内容。