简单说说Python
中的流程控制, 可以大致分为如下几类:
- 条件控制
- 循环控制
- 异常捕捉
Conditions
如上动画1便是条件控制的运行过程.
有的时候, 为了应对不止两个分支的情况, 我们使用elif
来在不满足if
对应的条件的情况下继续判断与执行程序:
1 | if a % 2 == 0: |
这段程式中使用elif
进行进一步判断, 如若if
对应的条件a % 2 == 0
不为真, 那么会进一步判断elif
所对应的条件a % 3 == 0
.
如若
a==56
则如上程式中a % 2 == 0
这一点是满足的,
那么解释器便不会考虑下面的其他情况, 直接运行相应的程式,
在这里便是输出:1
56 is even
如若
a==39
则如上程式中a % 3 == 0
这一点是满足的,
所以根据上述程式, 解释器会运行并输出如下:1
39 is odd and can be devided by 3
如若在
else
之前的情况皆不满足, 例如a == 5
时, 解释器会运行输出:1
5 is odd and cannot be devided by 3
总结一下使用if
进行条件判断的用法, 便可以简单理解为:
1 | if <conditon 1>: |
Loops
如上动画2便是循环控制的运行过程.
while
循环结构的格式类似于如下:
1 | while <condition>: |
同时我们也可以发现, 在
Python
中进行无限循环
的方法很简单, 那便是Python 1
2while True:
...为什么要提
无限循环
? 并不是我们真的想要让解释器无限地重复同一段代码直到机器报废自己退休甚至是下一次小行星重装地球, 而是因为有时在循环体内执行的操作很多, 退出循环体的需求也有很多, 此时便需要在所有需要退出的位置使用break
, 这也是我们稍后便要讲的.
除了while
之外, 我们还可以使用for
结构来进行循环, 其格式如下
1 | for <item> in <iterable>: |
这个结构比起说是循环
, 更像是在遍历
, 因为for ... in ...:
的意义为”对于某序贯
中的每一项
, 执行相应的重复操作”, 所以我们每次需要在<item>
的位置取临时变量名, 代表从<iterable>
中取用的每一个变量, 取执行循环体中的操作.
break
Usages
break
是Python
中的关键字, 用于提前结束正在进行的循环.
1 | for k in range(39): |
如上程式的输出如下
1 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, Interrupted!! |
其本应当输出从0
到38
, 但是只输出到9
, 便是因为在k == 10
的时候它满足条件k >= 10
, 触发了break
, 于是提前结束.
Exceptions
1 | import urllib.request, urllib.error |
通过上面这个例子, 我们可以很清楚地看出Python
进行异常捕捉的思路: 先进行试探性质的操作(try
部分), 然后列举需要捕捉的异常(except
部分), 如若程序在没有捕捉到任何异常的基础上, 正常地执行下去, 那么执行else
部分的操作, 最后也有不论如何执行都要进行的操作(finally
部分).
当然, 如若中途出现了没有捕捉的异常, 那么程式也会被中断!
except
关键字可以用于捕捉执行程序过程中出现的异常, 其语法用Python
的风格可以写作:
1 | except [SomeError [as alias]]: |
如上, 没有任何附加参数时, 单独的except
可以捕捉任何异常, 此外可以捕捉指定的异常, 如上例中的except urllib.error.HTTPError
(就是HTTP
协议相关的异常, 这个有机会的话会在后面网络信息采集里面进行讲解), 当且仅当发生了HTTPError
及其子类时这段except
会被激活并对其进行处理, 另外还可以使用as
来对捕捉的异常取别名, 方便在处理过程中调用, 例如上例中用err
代指HTTPError
, 用于读取HTTPError
发生时对应的HTTP
状态码(就是404 Not Found
或者403 Forbidden
那一套, 关于这个有个概念就好以后再细讲).
因此我们可以得到两种可以捕捉任何异常的方法:
1 | # Solution 1. |
但这两者有着本质上的区别!!: 前者是触发except
捕捉异常的基础功能, 后者是因为所有异常都是Exception
的子类!
else
Usages
else
这个关键字我们可以在很多计算机语言中见到, 不仅是C/C++
或Python
, 包括R
语言在流程控制中我们也可以见到
1 | x <- c("miku", "ichika", "saki") |
(其实文言里面也有若非
代替else
…)
1 | 若三不大於五者。 |
然而, 大部分语言中的else
只用于狭义的条件语句, 而在Python
中, 其还可以用于循环结构或异常处理.
方才已经展示了异常处理中的else
的用法, 现在我们来看循环结构中使用else
:
1 | for k in range(5): |
此时解释器会输出:
1 | MIKU! MIKU! MIKU! MIKU! MIKU! Finished! |
我们可以发现: 当循环运行结束之后 , else
部分的操作会被执行, 然而,
1 | for k in range(5): |
此时解释器会输出:
1 | MIKU! MIKU! MIKU! |
当循环提前结束的时候, else
部分便不会再执行.
我们综合上面看到的几种情况, 可以把else
的性质总结如下: else
在Python
中是一个关键字, 除了在if
引导的条件结构外, 可以用于循环结构和异常处理, 当且仅当这类过程没有被break
或抛出的异常打断之时.
Assertions
上面提到了Python
的异常及其捕捉系统, 事实上异常本身并非坏事! 这是一种用于判断程式执行中错误并紧急退出, 以免导致更大危险的处理方式. 在我们编写程式时, 也应考虑可能发生的错误, 在无法补救的时候抛出异常, 中断程式.
最简单的方式便是使用raise
关键字:
1 | raise Exception |
如若某个条件触发了这个异常的抛出, 程式则会中断并显示:
1 | --------------------------------------------------------------------------- |
不同的异常, 不论是哪个, 其归根结底皆为对象, 皆为类的实例化产物.
因此在抛出异常的时候, 对于大多数异常类, 需要使用构造函数对其进行初始化(但愿大家都学过面向对象).
如上的Exception
之所以可以直接抛出, 是因为其可以不指定参数调用构造函数进行初始化, 但不代表所有异常都可以这样抛出.
如下例中的urllib.error.HTTPError
便需要如上所言如一般类的实例化一样, 调用构造函数:
1 | import urllib.error |
有的时候, 在我们撰写类或函数的时候, 需要对使用者传入参数的变量进行限制, 此时便需要用到断言(assert
)机制:
1 | def transposition(arr: list): |
此时便会限定调用者传入的参数是一个形如[[ 3, 9 ]]
的嵌套列表, 如若不满足条件便会抛出异常如下:
1 | --------------------------------------------------------------------------- |
结合上面所说的异常的基本特征, 我们可以总结如下:
1 | assert <condition>, [message] |
这两者等价.
Attentions!!
我们有时会在C/C++
中看到如下被称为do-while
的循环结构
1 | do { |
这个在Python
中是从来都不存在的, 而且你如若需要的话可以在进入循环之前单独写一遍你所需要的过程.
References
1. 菜鸟教程 Python3
条件控制 ↩
2. 菜鸟教程 Python3
循环语句 ↩