Python Hacker程序员程序猿阵线联盟-汇总各类技术干货

Python基础手册18——复合语句(流程控制语句)

2018-01-19  本文已影响96人  常大鹏

复合语句

复合语句包含其他语句(组),它们以某种方式影响或控制那些其他语句的执行。一般来说,复合语句跨越多个逻辑行,虽然在简单形式中,整个复合语句可能包含在一行中。

复合语句由一个或多个 “子句” 组成,子句由 header 和 suite 组成。每一个 header 子句以一个唯一的标识关键字开始并以冒号结束。Suite 子句是由一条 header 子句控制的一组语句。一个 suite 子句可以是语句首冒号之后的同一行上紧跟一个或多个分号分隔的简单语句,也可以是后续行上一个或多个缩进的语句。只有后一种形式的 suite 子句可以包含嵌套复合语句。

复合语句主要包含:流程控制语句(if、while和for语句),异常处理语句(try语句),with语句和协程语句等。函数定义和类定义也是复合语句。这里我们主要介绍流程控制语句,其他复合语句会在后续的单独章节重点介绍。

流程控制语句:

Python 一般都会按照顺序从头到尾的执行文件中代码块中的语句,但是像 if、while
、for这样的语句会使得解释器的执行过程在程序内跳跃。这类会对正常执行顺序产生影响的语句,通常叫做流程控制语句。

一、if 语句

if 语句用于判断条件执行。它由三部分组成:关键字本身,用于判断结果真假的条件表达式,以及当表达式为真或者非零时执行的代码块。其形式是 if 测试语句后面跟着一个或多个可选的 elif 测试代码块,以及一个最终可选的 else 代码块。当 if 语句执行时,Python会执行第一个测试结果为真的语句下面的嵌套语句,如果所有测试都为假,就执行 else 部分,如果没有 else 部分,所有嵌套语句都不执行。

1、多重条件表达式

单个 if 语句可以通过使用布尔操作符 and , or 和 not 实现多重判断条件的组合。

2、单一语句的代码块

如果一个复合语句(例如 if 子句,while 或 for 循环)的代码块仅仅包含一行代码,那么它可以和前面的语句写在同一行上。

上边这样的单行语句是合法的,尽管它可能方便,但这样会使得代码更难阅读,所以我们推荐将这行代码移到下一行并合理地缩进。另外一个原因就是如果你需要添加新的代码,你还是得把它移到下一行。

3、else 语句

和其他语言一样, Python 提供了与 if 语句搭配使用的 else 语句。如果 if 语句的条件表达式的结果布尔值为假, 那么程序将执行 else 语句后的代码。

避免“悬挂 else”

Python 使用缩进而不是用大括号标记代码块边界的设计,不仅帮助强化了代码的正确性,而且还暗中帮助程序员避免了语法上正确的代码中存在的潜在问题。其中一个问题就是 "悬挂 else (dangling else)" 问题,在 C 语言中,规则是 else 与最近的 if 搭配,所以有时在视觉上会很难判断 else 语句所属的 if 语句。

Python 使用强制缩进使代码正确对齐,让程序员来决定 else 属于哪一个 if 。限制你的选择从而减少了不确定性,Python 鼓励你第一次就写出正确的代码。在 Python 中制造出“悬挂 else”问题是不可能的,而且,由于大括号不再被使用,Python 代码更易读懂。

4、elif 语句

elif 是 Python 的 else-if 语句,它检查多个表达式是否为真,并执行第一个为真的特定代码块中的代码。和 else 一样,elif 声明是可选的,然而不同的是,if 语句后最多只能有一个 else语句,但可以有任意数量的 elif 语句。

5、条件表达式(即"三元操作符")

三元运算符只使用一行语句就可以完成条件判断和赋值操作。

语法如下:

A = Y if X else Z

如果X为真则表达式的结果为Y,否则为Z。

二、while 语句

while 语句用于重复执行。它重复测试表达式,如果为真,则执行第一个 suite,直到表达式为假(也可能是第一次测试时),执行 else 子句的 suite(如果存在)并终止循环(也可能不存在else语句,这种情况则直接执行while循环下面的语句)。 while 循环的 suite 子句会一直循环执行,直到 expression 的值为假。这种类型的循环机制常常用在计数循环中。

1、无限循环

你必须小心地使用 while 循环,因为有可能 expression 永远不会为假。这样一来循环就永远不会结束。这些"无限"的循环不一定是坏事,许多通讯服务器的客户端/服务器系统就是通过它来工作的,这取决于循环是否需要一直执行下去。

2、else语句

如果在 while 循环正常执行完之后(没有break强制跳出)需要立刻执行某些语句,我们可以把这些语句放到 else语句里。

一般语法:

while expression:
    suite_to_repeat
else:
    suite_to_repeat

三、for 语句

for 语句是 Python 中的循环语句。它是一个通用的序列迭代器,可以遍历任何可迭代对象(例如序列或是迭代器)中的所有元素,并在所有条目都处理过后结束循环。不可能为死循环。

Python 的 for 循环的首行定义了一个赋值目标(或一些目标),以及你想遍历的可迭代对象。首行后面是你想重复执行的代码块(一般都有缩进)。

for 循环首先会对 expression_list 进行一次计算,产生一个可迭代的对象。然后为expression_list 的结果创建一个迭代器。for 循环会按照迭代器返回的顺序依次将每个项赋值给 target_list,然后为每个元素(target_list)执行 suite 子句。当元素用尽(当序列为空或迭代器引发StopIteration异常时,立即生效),执行 else 子句中的 suite 子句(如果存在且没有break跳出)并且循环终止。

for 循环首行中用作赋值目标的变量通常是 for 语句所在作用域中的变量(可能是新的)。

1、else 语句

for 语句也支持一个可选的 else 语句,他的工作就像是在 while 循环中一样:如果循环离开时没有碰到 break 语句,就会执行(也就是说序列中所有元素都访问过了)。
在第一个 suite 中执行的 break 语句会终止循环,而不执行 else 子句的 suite 。在第一个 suite 中执行的 continue 语句跳过这个 suite 的其余部分,并继续下一个项目,如果没有下一个项目,则继续使用 else 子句。

逐行读取文本文件时,for 循环是最简易也是最易于编写以及执行最快的选择。

这里 for 循环会按照文件迭代器来自动在每次循环迭代的时候读入一行。

2、for 循环中的序列赋值

如果迭代序列类型,循环目标本身可以是目标元祖。for循环把序列对象元素赋值给目标,而赋值运算在任何地方工作起来都是相同的。 for循环中的元组使得用 items() 方法遍历字典中的键和值变得很方便,而不必再遍历键时手动的索引字典来得到值。 但是字典的items() 方法会通过对字典所有的键取值来生成items()对象,然后再进行序列赋值,这种方法并没有直接索引字典的键然后取值来的高效。 即使是嵌套的结构赋值,在 for 循环中都是有效的。 我们也可以使用 Python 中的扩展的序列解包赋值语法,来提取序列中元素和部分。

3、内置函数 range()、zip() 和 enumerate()

一般而言,for 比 while 容易写,执行时也比较快。所以每当你需要遍历序列时,都应该把他作为首选的工具。同时,Python还内置了函数可以在 for 循环中定制迭代。

3.1 range() 内建函数

我们前面介绍 Python 的 for 循环的时候提到过它是一种迭代的循环机制。Python 同样提供一个工具让我们在传统的伪条件设置下使用 for 声明,例如从一个数字开始计数到另外个数字,一旦到达最后的数字或者某个条件不再满足就立刻退出循环。

内建函数 range() 是一个迭代器,会根据需要产生元素,可以把类似 foreach 的 for 循环变成你更加熟悉的语句。例如从 0 到10 计数,或者从 10 到 100 一次递增 5 。

Python 提供了两种不同的方法来调用 range() 。完整语法要求提供两个或三个整数参数:
range(start, end, step =1)

range() 会返回一个包含所有 k 的列表,这里 start <= k < end ,从 start 到 end , k 每次递增

step 。step 不可以为零,否则将发生错误。 如果只给定两个参数,而省略 step,step 就使用默认值 1 。

rang还有一种简略的语法格式,使用一个参数时,range会产生从零算起的整数列表,但其中不包括改参数的值。:
range(end)

这个时候,则start 默认为0,step默认为1。 使用 range() 和 for 的组合的常见场合就是在循环中遍历列表时并对其进行修改。而等效的 while 循环不仅会让我们多写一些代码,还可能运行的更慢。

除非你有特殊的索引需求,不然在可能的情况下,最好使用 Python 中的简单的 for 循环,不要使用 while,并且不要在 for 循环中使用 range() 调用,只将其视为最后的手段。

3.2 zip() 内建函数

内置的 zip() 函数可以让我们使用 for 循环来并行使用多个序列。在基本运算中,zip() 函数会取得一个或多个序列为参数,然后返回元祖的列表,将这些序列中的并排的元素配成对。 zip() 函数可以接受任何类型的序列(其实是任何可迭代的对象,包括文件),并且可以有两个以上的参数。当参数长度不同时,zip会以最短序列的长度为准来截断所得到的参数。 当要构建的字典的键和值必须在运行的时后计算得到时,这里使用 zip() 生成字典会非常方便。

3.3 enumerate() 内建函数

在有些过程中我们会同时需要序列对象的元素和元素的偏移值,for循环支持一个记录当前偏移值的计数器 enumerate()。enumerate() 函数返回一个生成器对象,这个对象有一个next方法,由下一个内置函数调用它,并且循环中每次迭代的时候它都会返回一个(index, value)的元组。

四、用在复合语句中的简单语句

1、break语句

Python 中的 break 语句可以结束当前循环(包括循环后面的else语句)然后跳转到下条语句,break 语句用在 while 和 for 循环中。

2、continue语句

Python 里的 continue 语句可以用在 while 和 for 循环里。当遇到 continue 语句时, 程序会终止当前循环,并忽略剩余的语句,然后回到循环的顶端。在开始下一次迭代开始前,如果是条件循环,我们将验证条件表达式。如果是迭代循环,我们将验证是否还有元素可以迭代。只有在验证成功的情况下,我们才会开始下一次迭代。

3、pass语句

由于Python 没有使用传统的大括号来标记代码块,所以没有对应的空大括号或是分号( ; )来表示 C 语言中的 "不做任何事" 。如果你在需要子语句块的地方不写任何语句,解释器会提示你语法错误。因此, Python 提供了 pass 语句,它不做任何事情 - 即NOP ,只是一个无运算的空的占位语句。当语法需要语句并且还没有任何使用的语句可写时,就可以使用它。它通常用于为复合语句编写一个空的主体。

这样的代码结构在开发和调试时很有用,因为编写代码的时候你可能要先把结构定下来,但你不希望它干扰其他已经完成的代码。在不需要它做任何事情地方,放一个 pass 将是一个很好的主意。

另外它在异常处理中也被经常用到:比如你跟踪到了一个非致命的错误,不想采取任何措施(你只是想记录一下事件或是在内部进行处理。

《Python基础手册》系列:

Python基础手册 1 —— Python语言介绍
Python基础手册 2 —— Python 环境搭建(Linux)
Python基础手册 3 —— Python解释器
Python基础手册 4 —— 文本结构
Python基础手册 5 —— 标识符和关键字
Python基础手册 6 —— 操作符
Python基础手册 7 —— 内建函数
Python基础手册 8 —— Python对象
Python基础手册 9 —— 数字类型
Python基础手册10 —— 序列(字符串)
Python基础手册11 —— 序列(元组&列表)
Python基础手册12 —— 序列(类型操作)
Python基础手册13 —— 映射(字典)
Python基础手册14 —— 集合
Python基础手册15 —— 解析
Python基础手册16 —— 文件
Python基础手册17 —— 简单语句
Python基础手册18 —— 复合语句(流程控制语句)
Python基础手册19 —— 迭代器
Python基础手册20 —— 生成器
Python基础手册21 —— 函数的定义
Python基础手册22 —— 函数的参数
Python基础手册23 —— 函数的调用
Python基础手册24 —— 函数中变量的作用域
Python基础手册25 —— 装饰器
Python基础手册26 —— 错误 & 异常
Python基础手册27 —— 模块
Python基础手册28 —— 模块的高级概念
Python基础手册29 —— 包

上一篇下一篇

猜你喜欢

热点阅读