一些关于流程控制的语法,没什么好说的,各种语言都大同小异,直接给例子即可。

条件语句

if 条件

直接给例子,只需要注意一下用elif而非else if

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if a==1:
...

if x<0:
...
else:
...

if x<0:
...
elif x==0:
...
else:
...

最简单的单行 if 也是可以的

1
if True: print("hello")

还可以使用如下的单行 if 表达式,类似于 C 语言的三目运算符,它算作表达式,因此也可以用在 lambda 表达式中

1
2
3
result = 1 if True else -1 # 1

result = (lambda : 1 if 3>4 else -1)() # -1

注意:在 if 中的条件可以包括与或非等更复杂的逻辑判断,但是只能使用 and or not 来代表,不支持 && || !;(C++对这两套都支持,但是主要使用后者)

match 匹配

Python 早期不支持 switch 语句,只能用 if 语句,较新的版本加上了与之类似的match语句。 match语句支持比C++的switch更复杂的逻辑,后者只能基于一个整数判断,前者甚至可以进行正则匹配,这里不做讨论。

例如

1
2
3
4
5
6
7
8
9
10
def http_error(status):
match status:
case 400:
return "Bad request"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _:
return "Something's wrong with the internet"

循环语句

Python的循环语句效率非常低,对运行效率有要求时应尽量避免使用,可以使用numpy提供的向量化操作、列表推导式等进行替代。

while 循环

直接给例子即可

1
2
3
4
5
6
7
8
9
10
11
a=1
while a<5:
a+=1
print(a)

'''
2
3
4
5
'''

最简单的单行 while 也是可以的

1
2
a=2
while a<10: print("hello");a=a+1

for 遍历

Python 的 for 语句只能基于一个可遍历的对象(列表,元组,字典等),因此称为 for 遍历比 for 循环更合适。

对于列表、元组和集合,for 循环可以获取其中的每一项

1
2
3
4
words = ['a1','b1','c1']

for w in words:
...

对于字典,for 循环获取的是每一个键值对中的键,而不是对应的值!

1
2
3
4
5
6
7
dict = {'a':1,'b':2}

for i in dict:
print("key:",i,i.__class__,"value:",dict[i])

# key: a <class 'str'> value: 1
# key: b <class 'str'> value: 2

注意:

  • 和 C++的迭代器一样,在过程中尝试修改遍历对象的行为是不可控的!如果需要修改,考虑遍历此对象的副本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    users = {'Hans': 'active', 'Éléonore': 'inactive', '景太郎': 'active'}

    # 遍历副本,修改原对象
    for user, status in users.copy().items():
    if status == 'inactive':
    del users[user]

    # 遍历原对象,创建一个新对象
    active_users = {}
    for user, status in users.items():
    if status == 'active':
    active_users[user] = statu

  • for 遍历语句中的临时变量并不会在退出遍历时被自动删除,而是仍然保留着遍历过程中的最后一项的值,在后文中仍然可用,for 语句并不能开辟一个独立的作用域,但是如果遍历一次都没有执行,那么临时变量不会被赋值

for range 遍历

对于 C/C++的 for 语法功能,在 Python 中需要通过 range() 函数来辅助实现,或者用 while 实现。

range() 只能使用整数参数,含义如下:

  • 三个参数 a,b,c 代表从 a 开始,每次增加的步长为 c(c可以是负数),到 b 停止(不含 b)
    • 若步长c>0,相当于for(i=a,i<b,i=i+c)
    • 若步长c<0,相当于for(i=a,i>b,i=i+c)
  • 两个参数 a,b 代表从 a 开始,每次增加的步长默认为 c=1,到 b 停止(不含 b)
  • 一个参数 b 代表默认从 a=0 开始,每次增加的步长默认为 c=1,到 b 停止(不含 b)

例如

1
2
3
4
5
6
7
8
range(5)
# 0,1,2,3,4
range(3,6)
# 3,4,5
range(3,10,2)
# 3,5,7,9
range(10,3,-2)
# 10,8,6,4

使用 for range() 可以实现 C 风格的 for 循环,例如

1
2
3
4
5
6
7
8
9
for i in range(3,10,2):
print(i)

'''
3
5
7
9
'''

break和continue语句

break 和 continue 就是编程语言中普遍采用的含义:

  • break 语句可以直接跳出一层 for 或者 while 循环,对于多层循环只能跳出最内层的一层。
  • continue 语句可以直接进入下一轮循环中,跳过当前循环的剩余部分。

else语句

在 while 循环和 for 遍历结构中,我们可以附带 else 分支语句, 在循环正常结束(而非通过break跳出循环)时触发,例如

  • while 循环遇到判断条件为 False 时正常退出
  • for 遍历正常结束(默认会捕获遍历终止的异常)

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
digits = [0, 1, 2, 3, 4]

for i in digits:
print(i)
else:
print("end")

# 0
# 1
# 2
# 3
# 4
# end

for i in digits:
print(i)
if i >2: break
else:
print("end")

# 0
# 1
# 2
# 3

补充

有几个函数经常在循环语句中使用,这里补充介绍。

zip 函数

zip 函数可以将两个可迭代对象(列表/元组等)的对应项一一对应包装为元组,然后返回一个可迭代的 zip 对象,相当于一个字典的效果。如果两个列表长度不一样,以短的为准,多余的部分被丢弃。

注意这里 for 循环遍历的每一项是含有两个元素的元组,因此可以用两个变量直接解包

1
2
3
4
5
6
7
8
9
10
a = [1,2,3]
b = ['a','b','c','d']


for i,j in zip(a,b):
print(i,j)

# 1 a
# 2 b
# 3 c

enumerate 函数

enumerate 函数和 zip 类似,只不过只需要一个列表,会自动给这个列表添加从 0 开始序号,得到一个元组(序号在前,列表元素在后),在 for 遍历中非常方便,因为不仅仅需要迭代的每一项,还需要当前的遍历序号。

1
2
3
4
5
6
7
8
animals = ["dog", "cat", "mouse"]

for i, value in enumerate(animals):
print(i, value)

# 0 dog
# 1 cat
# 2 mouse

海象运算符

在if和while语句中,我们需要对一个变量或表达式进行判断,在Python中提供了一个海象运算符可以将逻辑判断和变量赋值结合到一起, 注意这里的变量在if和while语句退出之后仍然可以使用。

在if语句中的用法例如

1
2
if (x := len('hello')) > 3:
print(f"The length of 'hello' is {x}")

相当于

1
2
3
x = len('hello')
if x>3:
print(f"The length of 'hello' is {x}")

while语句的用法也是类似的,例如

1
2
3
file = open("demo.txt", "r")
while (line := file.readline()):
print(line.strip())

相当于

1
2
3
4
5
6
file = open("demo.txt", "r")
while True:
line = file.readline()
if not line:
break
print(line.strip())

异常处理

异常处理的流程非常类似于 C++,与C++不同的是在 Python 中并没有严格的函数调用栈之类的,一切都是 Python 解释器提供的动态对象。

捕获异常

捕获异常的语法结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try: #执行某些不安全的代码
pass

except ValueError: # 处理ValueError异常
pass

except (TypeError, ZeroDivisionError) # 处理多个异常: TypeError 和 ZeroDivisionError 异常
pass

except: # 处理所有其他异常
pass

else: # 没有异常时进入的分支
pass

[finally:] # 无论try运行中是否抛出异常,最后总是会执行这一部分,例如执行文件关闭,状态恢复,清理现场
pass

例如,下文遍历一个列表直到找到一个有效数据可用于计算倒数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import sys

for entry in ['a', 0, 2]:
try:
print("The entry is", entry)
r = 1/int(entry)
break
except:
print("Oops!",sys.exc_info()[0],"occured. Next entry.\n")

print("The reciprocal of",entry,"is",r)

'''
The entry is a
Oops! <class 'ValueError'> occured. Next entry.

The entry is 0
Oops! <class 'ZeroDivisionError'> occured. Next entry.

The entry is 2
The reciprocal of 2 is 0.5
'''

抛出异常

除以 0 的操作可以触发一个 ZeroDivisionError 异常,同样地,我们可以自行在语句中使用raise语句抛出异常,例如

1
2
3
4
5
6
try:
a = int(input("Please input a positive number"))
if a <= 0:
raise ValueError("Not positive!")
except ValueError as ve:
print(ve)

上文中如果输入不满足要求,会抛出 Python 提供的 ValueError 异常,然后立刻捕获异常。

和 C++一样,Python 支持自定义异常,但是要求继承标准异常类 Exception,略。

断言assert

类似于C语言的assert,在运行时断言表达式为真:如果为真则无事发生,否则抛出异常。

第一种形式

1
assert expression

大致相当于

1
2
if __debug__:
if not expression: raise AssertionError

第二种形式会附加信息

1
assert expression1, expression2

大致相当于

1
2
if __debug__:
if not expression1: raise AssertionError(expression2)

例如

1
2
3
assert x>1

assert ('linux' in sys.platform), "该代码只能在 Linux 下执行"