什么是控制流:
编程语言中的控制流(Control flow)语句用于控制各操作执行的顺序。
一段没有控制流的程序的操作顺序应当是这样的:
但是实际生活中,顺序操作并不总是能够满足我们的需求,我们可能需要对流程中的一些步骤加入控制。
举个例子,当我们在揉面团的时候,我们首先加入面粉,再倒入一点点水,之后我们还要 判断 目前的加入的水量是否合适,如果过干,需要再加入一点点水,循环 这个步骤,直到我们认为面粉和水的配比合适为止。
上面的这个流程中就包含了 判断 和 循环 两种控制流处理。
条件语句
If 语句
if
语句是是一种条件语句,根据条件为 true 还是 false 运行或执行相关代码。下面是一个简单的示例:
if phone_balance < 5:
phone_balance += 10
bank_balance -= 10
我们来详细讲解下每部分。
if
语句以关键字if
开始,然后是要检查的条件,在此例中是phone_balance < 5
,接着是英文冒号。条件用布尔表达式指定,结果为 True 或 False。- 这行之后是一个条件为 true 时将执行的缩进代码块。在此例中,仅在
phone_balance
小于 5 时才执行使phone_balance
递增和使bank_balance
递减的行。如果不小于 5,这个if
块中的代码将被跳过。
If、Elif、Else
除了 if
条件之外,if
语句经常还会使用另外两个可选条件。例如:
if season == 'spring':
print('plant the garden!')
elif season == 'summer':
print('water the garden!')
elif season == 'fall':
print('harvest the garden!')
elif season == 'winter':
print('stay indoors!')
else:
print('unrecognized season')
if
:if
语句必须始终以if
条件开始,其中包含第一个要检查的条件。如果该条件为 True,Python 将运行这个if
块中的缩进代码,然后跳到if
语句之后的剩余代码。elif
:elif
条件用来检查其他条件(前提是if
语句中之前的条件结果为 False)。可以从示例中看出,可以使用多个elif
块处理不同的情形。else
:最后是else
条件,它必须位于if
语句的末尾。该条件语句不需要条件。如果if
语句中所有前面的语句结果都为 False 时,将运行else
块中的代码。
缩进
一些其他语言使用花括号来表示代码块从哪开始,从哪结束。在 Python 中,我们使用缩进来封装代码块。例如,if
语句使用缩进告诉 Python 哪些代码位于不同条件语句里面,哪些代码位于外面。
在 Python 中,缩进通常是四个空格一组。请严格遵守该惯例,因为更改缩进会完全更改代码的含义。如果你是 Python 程序员团队的成员,则所有人都必须遵守相同的缩进惯例!
条件布尔表达式
复杂的布尔表达式
If
语句有时候会使用更加复杂的条件布尔表达式。可能包括多个比较运算符、逻辑运算符,甚至包括算式。例如:
if 18.5 <= weight / height**2 < 25:
print("BMI is considered 'normal'")
if is_raining and is_sunny:
print("Is there a rainbow?")
if (not unsubscribed) and (location == "USA" or location == "CAN"):
print("send email")
对于非常复杂的条件,你可能需要结合使用 and
、or
和 not
。使用括号可以使运算符组合更清晰。
无论是简单还是复杂的条件,if
语句中的条件都必须是结果为 True 或 False 的布尔表达式,该值决定了 if
语句中的缩进代码块是否执行。
正反面示例
在为 if
语句编写布尔表达式时,需要注意以下几个事项。
1. 请勿使用 True
或 False
作为条件
# Bad example
if True:
print("This indented code will always get run.")
虽然“True”是一个有效的布尔表达式,但不是有用的条件,因为它始终为 True,因此缩进代码将始终运行。同样,if False
也不应使用,该 if
语句之后的语句将从不运行。
# Another bad example
if is_cold or not is_cold:
print("This indented code will always get run.")
同样,使用你知道将始终结果为 True 的条件(例如上述示例)也是毫无用途的。布尔表达式只能为 True 或 False,因此 is_cold
或 not is_cold
将始终为 True,缩进代码将始终运行。
2. 在使用逻辑运算符编写表达式时,要谨慎
逻辑运算符 and
、or
和 not
具有特定的含义,与字面英文意思不太一样。确保布尔表达式的结果和你预期的一样。
# Bad example
if weather == "snow" or "rain":
print("Wear boots!")
这段代码在 Python 中是有效的,但不是布尔表达式,虽然读起来像。原因是 or
运算符右侧的表达式 "rain"
不是布尔表达式,它是一个字符串。稍后我们将讨论当你使用非布尔型对象替换布尔表达式时,会发生什么。
3. 请勿使用 == True
或 == False
比较布尔变量
这种比较没必要,因为布尔变量本身是布尔表达式。
# Bad example
if is_cold == True:
print("The weather is cold!")
这是一个有效的条件,但是我们可以使用变量本身作为条件,使代码更容易读懂,如下所示。
# Good example
if is_cold:
print("The weather is cold!")
如果你想检查布尔表达式是否为 False,可以使用 not
运算符。
00:00 / 01:28
1.25x
CC
真假值测试
如果我们在if
语句中使用非布尔对象代替布尔表达式,Python 将检查其真假值,判断是否运行缩进代码。默认情况下,Python 中对象的真假值被视为 True,除非在文档中被指定为 False。
以下是在 Python 中被视为 False 的大多数内置对象:
- 定义为 false 的常量:
None
和False
- 任何数字类型的零:
0
、0.0
、0j
、Decimal(0)
、Fraction(0, 1)
- 空序列和空集合:
””
、()
、[]
、{}
、set()
、range(0)
示例:
errors = 3
if errors:
print("You have {} errors to fix!".format(errors))
else:
print("No errors to fix!")
在上述代码中,errors 的真假值为 True,因为它是非零数字,因此输出了错误消息。这是一个编写 if
语句的简练方式。
下一项
For 循环
Python 有两种类型的循环:for
循环和 while
循环。for
循环用来遍历可迭代对象。
可迭代对象是每次可以返回其中一个元素的对象,包括字符串、列表和元组等序列类型,以及字典和文件等非序列类型。你还可以使用迭代器和生成器定义可迭代对象,我们将在这门课程的稍后阶段详细了解迭代器和生成器。
我们来了解下 for
循环的各个组成部分。请看下面的示例:
# iterable of cities
cities = ['new york city', 'mountain view', 'chicago', 'los angeles']
# for loop that iterates over the cities list
for city in cities:
print(city.title())
For 循环的组成部分
- 循环的第一行以关键字
for
开始,表示这是一个for
循环 - 然后是
iteration_variable in iterable
,表示正在被遍历的是可迭代的对象,并且用迭代变量表示当前正在被处理的可迭代对象的元素。在此示例中,迭代变量city
在第一次迭代时将是“new york city”,在第二次迭代时将是“mountain view。 for
循环头部始终以英文冒号:
结束。for
循环头部之后的是在此for
循环的每次迭代时运行的缩进代码块。在此块中,我们可以使用迭代变量访问当前正在被处理的元素的值。
你可以随意命名迭代变量。常见模式是为迭代变量和可迭代对象指定相同的名称,但是分别使用单复数形式(例如 'city' 和 'cities)
创建和修改列表
除了从列表中提取信息之外,你还可以使用 for
循环创建和修改列表。你可以在 for
循环的每次迭代时向新列表中添加元素,创建一个列表。如下所示。
# Creating a new list
cities = ['new york city', 'mountain view', 'chicago', 'los angeles']
capitalized_cities = []
for city in cities:
capitalized_cities.append(city.title())
修改列表稍微复杂些,需要使用新的函数:range()
。
range()
是一个内置函数,用于创建不可变的数字序列。它有三个参数,必须都为整数。
range(start=0, stop, step=1)
Start
是该序列的第一个数字,stop
比该序列的最后一个数字大 1,step
是该序列中每个数字之间的差。如果未指定的话,start
默认为 0,step
默认为 1(即上述 =0
和 =1
)。
- 如果你在
range()
的括号里指定一个参数,它将用作 'stop' 的值,另外两个参数使用默认值。
E.g.list(range(4))
返回[0, 1, 2, 3]
- 如果你在
range()
的括号里指定两个参数,它们将用作 'start' 和 'stop' 的值,'step' 将使用默认值。 E.g.list(range(2, 6))
返回[2, 3, 4, 5]
- 或者你可以为三个参数 'start、stop' 和 'step' 均指定一个值。 E.g.
list(range(1, 10, 2))
返回[1, 3, 5, 7, 9]
注意,在这些示例中,我们将 range
封装在列表中。因为 range
本身的输出是一个 range
对象。我们可以通过将其转换为列表或在 for
循环中遍历它,查看 range
对象中的值集合。
我们可以使用 range
函数为 cities
列表中的每个值生成索引。这样我们便可以使用 cities[index]
访问列表中的元素,以便直接修改 cities
列表中的值。
cities = ['new york city', 'mountain view', 'chicago', 'los angeles']
for index in range(len(cities)):
cities[index] = cities[index].title()
虽然修改列表是 range
函数的一个用途,但是并非只有这一个用途。你将经常使用 range
和 for
循环重复某个操作一定的次数。
While 循环
For
循环是一种“有限迭代”,意味着循环主体将运行预定义的次数。这与“无限迭代”循环不同,无限迭代循环是指循环重复未知次数,并在满足某个条件时结束,while
循环正是这种情况。下面是一个 while
循环的示例。
card_deck = [4, 11, 8, 5, 13, 2, 8, 10]
hand = []
# adds the last element of the card_deck list to the hand list
# until the values in hand add up to 17 or more
while sum(hand) <= 17:
hand.append(card_deck.pop())
这个示例包含两个函数。sum
返回列表中的元素之和,pop
是一个列表方法,它会从列表中删除最后一个元素并返回该元素。
While
循环的组成部分
- 第一行以关键字
while
开始,表示这是一个while
循环。 - 然后是要检查的条件。在此示例中是
sum(hand) <= 17
。 while
循环头部始终以冒号:
结束。- 该头部之后的缩进部分是
while
循环的主体。如果while
循环的条件为 true,该循环的主体将被执行。每次运行循环主体时,条件将被重新评估。这个检查条件然后运行循环的流程将重复,直到该表达式变成 false。
循环的缩进主体应该至少修改测试表达式中的一个变量。如果测试表达式的值始终不变,就会变成无限循环!
Break、Continue
Break、Continue
有时候我们需要更精准地控制何时循环应该结束,或者跳过某个迭代。在这些情况下,我们使用关键字 break
和 continue
,这两个关键字可以用于 for
和 while
循环。
break
使循环终止continue
跳过循环的一次迭代
Zip 和 Enumerate
zip
和 enumerate
是实用的内置函数,可以在处理循环时用到。
Zip
zip
返回一个将多个可迭代对象组合成一个元组序列的迭代器。每个元组都包含所有可迭代对象中该位置的元素。例如,
list(zip(['a', 'b', 'c'], [1, 2, 3]))
将输出 [('a', 1), ('b', 2), ('c', 3)]
.
正如 range()
一样,我们需要将其转换为列表或使用循环进行遍历以查看其中的元素。
你可以如下所示地用 for
循环拆分每个元组。
letters = ['a', 'b', 'c']
nums = [1, 2, 3]
for letter, num in zip(letters, nums):
print("{}: {}".format(letter, num))
除了可以将两个列表组合到一起之外,还可以使用星号拆分列表。
some_list = [('a', 1), ('b', 2), ('c', 3)]
letters, nums = zip(*some_list)
这样可以创建正如之前看到的相同 letters
和 nums
列表。
Enumerate
enumerate
是一个会返回元组迭代器的内置函数,这些元组包含列表的索引和值。当你需要在循环中获取可迭代对象的每个元素及其索引时,将经常用到该函数。
letters = ['a', 'b', 'c', 'd', 'e']
for i, letter in enumerate(letters):
print(i, letter)
这段代码将输出:
0 a
1 b
2 c
3 d
4 e
练习:Zip 和 Enumerate(选学
列表推导式
在 Python 中,你可以使用列表推导式快速简练地创建列表。下面是之前的一个示例:
capitalized_cities = []
for city in cities:
capitalized_cities.append(city.title())
可以简写为:
capitalized_cities = [city.title() for city in cities]
借助列表推导式,我们可以使用 for
循环用一步创建一个列表。
我们使用方括号 []
创建列表推导式,括号里包含要对可迭代对象中的每个元素进行评估的条件。上述列表推导式对 cities
中的每个元素 city
调用 city.title()
,以为新列表 capitalized_cities
创建每个元素。
列表推导式中的条件语句
你还可以向列表推导式添加条件语句。在可迭代对象之后,你可以使用关键字 if
检查每次迭代中的条件。
squares = [x**2 for x in range(9) if x % 2 == 0]
上述代码将 squares
设为等于列表 [0, 4, 16, 36, 64],因为仅在 x 为偶数时才评估 x 的 2 次幂。如果你想添加 else
,将遇到语法错误。
squares = [x**2 for x in range(9) if x % 2 == 0 else x + 3]
如果你要添加 else
,则需要将条件语句移到列表推导式的开头,直接放在表达式后面,如下所示。
squares = [x**2 if x % 2 == 0 else x + 3 for x in range(9)]
列表推导式并没有在其他语言中出现,但是在 python 中很常见。