探索Python,第5部分:用Python编程

转载:http://www-128.ibm.com/developerworks/cn/opensource/os-python5/
控制流
级别:中级
Robert Brunner
(
[email=rb@ncsa.uiuc.edu?subject=%E7%94%A8%20Python%20%E7%BC%96%E7%A8%8B]rb@ncsa.uiuc.edu[/email]
), 研究专家, National Center for Supercomputing Applications
2005 年  10 月  31 日
    本文开始讲述如何用Python编程,着重点是流控制,这是编写程序的最简方法之一。在该编程模型中,会操纵来自用户界面、传感器或文件等的数据,根据数据的值或产生的表达式不同,采取的操作也不同。Python提供几种流控制机制。本文将讨论if语句、while循环和for循环。
程序流
    该“探索Python“系列的前4篇文章介绍了Python程序中常用的基本数据类型,包括:
        * 内置的数值数据类型
        * Tuple容器类型
        * String容器类型
        * List容器类型
    该系列的前4篇文章也展示了一些简单的Python例子,这些例子管理保存有这四种类型的数据的变量。尽管我没有指出,但是我自然还是假设您像读一本书一样地读并解释代码。(至少英语中)自然的顺序是从页面或程序的顶端开始,然后从左往右读每一行。当达到行尾后,又是下一行的开始(或者叫做左端),依此类推,沿着页面(这里是指程序)往下走。
    Python解释器在其最简单的级别,以类似的方式操作,即从程序的顶端开始,然后一行一行地顺序执行程序语句。例如,清单1展示了几个简单的语句。当把它们键入Python解释器中(或者将它们保存在一个文件中,并作为一个Python程序来执行)时,读取语句的顺序是从左到右。当读到一个行结束符(比如换行符)时,Python解释器就前进到下一行并继续,直到没有了代码行。
清单1. 一个简单的Python程序
>>> i = 1
>>> type(i)
>>> l = [0, 1, 2, 3, 4]
>>> l * i
[0, 1, 2, 3, 4]
    在本例中,语句以简单的顺序一个接一个。但是情况并不总是线性的。考虑一个个人的例子。您今天早上醒来,听了交通或天气报告(或者两者都听了)。根据交通报告,您可能选择了一条不同的上班路线;或者类似地,根据天气报告,您为周末计划了不同的活动。您的对策并不简单;根据您所获得的信息,生活的自然顺序迂回而曲折。
    Python像大多数编程语言一样,通过使用流控制语句,也可以以这种方式操作。在Python中,有3种基本的流控制语句:
        * if语句,它基于测试表达式的结果执行一个特定的语句块。
        * while循环,它当一个测试表达式为true时执行一个语句块。
        * for循环,它对一个语句块执行一定次数。
    这个列表相当简单,并且您可能从其他编程语言认识了这些流控制语句。但是您可能在想,语句块是什么意思呢。在清单1中,您看到了几个简单的语句,包括一个变量初始化、一个方法调用(type方法)和一个乘法操作。这些语句执行一个简单的操作,因此把它们叫做简单语句。
    Python也具有复合语句,即相关语句形成的语句组,其中包括简单和(可能)附加的复杂语句。例如,根据表达式的值(对个人来说,可能是对“今天的天气晴朗吗”之类问题的答案),一个复合语句可能执行不同的操作或者对一个操作重复多次。这一描述似乎有些类似于前一段的流控制描述。当然应该类似,因为流控制语句就是复合语句。
    一个复合语句包括一个流控制指令,后跟一个冒号(:),然后再是一个程序语句块。语句块由一个或多个简单语句和复合语句组成。清单2中提供了一个简单的伪代码例子。
清单2. 一个伪代码例子展示了简单语句和复杂语句
simple statement one
compound statement one:
    simple statement two
    simple statement three
    compound statement two:
        simple statement four
simple statement five
    该语法看起来既熟悉又陌生,并且两种感觉来自相同的事情:缩进。在列大纲或步骤时,您可能会使用不同级别的缩进来分隔每一项,使得列出来的东西更加清晰可读。Python遵循这一模型,使用缩进来分隔代码块与程序的其余部分。其他编程语言使用特殊的字符来区分代码块,比如基于C的语言中的花括号({ 和 })。这些其他语言也鼓励程序员使用缩进,以改善程序的可读性。
    另一方面,Python需要缩进以指示代码块。如果没有正确地缩进,Python解释器会抛出异常。可以使用制表符来标记缩进,但是一般推荐使用空格。(为了一致性,我总是使用4个空格来缩进代码块。)理由很简单:空格字符只有一种解释方式。另一方面,制表符可以有不同的解释方式,根据所使用的平台或工具,可以解释为 2 个、4 个、6 个甚至 8 个空格。
增强程序可读性
    缩进要求可能是Python的一个基本指导原则——Python程序应该易于读和理解——的最佳例子。但是这就跟工具一样,顽固分子也可能会编写晦涩的Python代码。例如,螺丝起子是用来起螺丝的,但是有时您也可能用来打开油漆盖子。
    两个其他特性有助于编写易读的Python程序,并且这两者都遵循前面所用的书的比喻。首先,书中的行不会延伸到页面外面,都有固定的长度。其次,书中的行不是以特殊符号(比如分号)结束。这两个特性都贯穿于编写Python程序的过程中。
    如果某个程序行太长,可以在文件中的下一物理行继续这一行。没有硬性规定一个代码行应该多长。但是一般限制为80个字符,这容易适合大多数显示器的一个打印页面。有几种方式来扩展超过一行的代码语句:
        * 三引号字符串可以扩展到多个行。
        * 括号中的表达式可以扩展到多个行。
        * 可以使用继续字符(\)来在多行分割语句。
    在Python 中,不需要使用特殊字符(或符号)来指示语句的结束。这与有些语言不同。例如,基于C的语言使用分号(;)来指示代码行的结束。然而,有时候需要在一行放多个程序语句,例如初始化变量时。在这样的情况下,可以使用分号来分隔单个语句。
    清单3中演示了这两种技术。
清单3. 演示Python的可读性技术
>>> i1 = 10 ; i2 = 20 ; i3 = 30
>>>
>>> b = ((i1 >> b
True
>>>
>>> b = (i1 >>
>>> b
True
    注意清单3中扩展到多个行的程序语句是如何缩进以改善可读性的。在本例中,缩进不是强制性的,就跟一个复合语句一样。但是正如您所见,缩进改善了程序的外观,因而强烈推荐进行缩进。
if语句
    最简单的流控制语句是if语句,它的基本语法在清单4中的伪代码中演示了。if语句在一个布尔表达式计算为True时执行一个程序语句块。if语句支持一个可选的else子句,指示当布尔表达式计算为False时应该处理的程序语句块。
清单4. if语句的基本语法
if(expression one):
    # Action to take if expression one evaluates True
else:
    # Action to take if all expression one evaluates False
    如果您使用过其他编程语言,那么该语法看起来可能既熟悉又陌生。相似之处在于if语句的一般格式、名称、用于确定如何分支语句执行流的表达式的计算,以及用于处理当表达式计算为False时的情况的else子句。但是有两个方面是完全特定于Python 的:带有冒号字符的if和else语句的终止,以及if和else块中语句的缩进。正如所提到的,这两个特征是Python中流控制语句所必需的。
    在清单5中,一个简单的if/else条件测试一个给定的数字是奇数还是偶数,并打印出结果。
清单5. 一个简单的if语句例子
>>> i = 8
>>> if(i % 2):
...     print "Odd Number"
... else:
...     print "Even Number"
...
Even Number
    一个似乎有些混乱的地方是if语句后面每一行前面的三个点(...)。当键入if语句和终止的冒号,并按键盘上的回车键时,Python解释器就知道您输入了一个复合语句。因此,它就将提示符从三个大于符号(>>>)改为三个点(...)。因为Python需要缩进以错开当表达式计算为True或False时应该执行的语句块,所以两个print语句都缩进了4个空格。
    if语句(以及本文后面讨论的elif子句和while循环)中的表达式可以很复杂。它可以包括多个使用 Python中支持的不同关系运算符的子表达式。而子表达式又可使用and、or和not逻辑运算符组合起来。本系列的第一篇文章“探索 Python,第1部分:Python的内置数值类型”,包含更多关于布尔表达式和Python中不同关系和逻辑运算符的信息。
    至此,已经看到了if语句可以如何用于根据一个特定布尔表达式的值,来执行两个程序语句块中的其中一个。然而在有些情况下,可能需要更多的选择。幸运的是,Python提供了if语句的一个简单扩展。提供的解决方案非常简单:给else子句添加一个额外的if语句,结果是一个else if语句,简写为elif,如清单 6 所示。
清单6. 使用elif语句
>>> i = -8
>>> if(i > 0):
...     print "Positive Integer"
... elif(i
    本例只包含一个elif语句,而实际中可根据程序需要包含任意多个。尽管它不是最优的解决方案,但是多个elif语句可以用于模拟其他一些语言中的switch case语句。
while循环
    Python中的第二种流控制语句是while循环,它在一个表达式计算为True时执行一个程序语句块。while循环与if语句一样,支持一个可选的else子句,其中包含一个当表达式计算为False时执行的程序语句块。但是对于while循环,这意味着在循环终止后,else子句中的代码被执行一次(参见清单7中的伪代码)。
清单7. while循环的伪代码
while (expression):
    # statements to execute while loop expression is True
else:
    # statements to execute when loop expression is False
    理解了if语句之后,while循环理解起来就相当简单了。但是一定要知道,循环一直要执行到表达式计算为False。这意味着循环体中执行的程序语句必须要改变表达式的值,否则循环将无法结束。如清单8所示。
清单8. while循环的一个简单例子
>>> i = 0 ; x = 10
>>> while(x > 0):
...     i+=1 ; x -= 1
... else:
...     print i, x
...
10 0
    该例演示了几件事情。首先,它在一行中组合了变量初始化和变量修改:在本例中是i和x变量。其次,分别使用缩写形式的运算符+=和-=来递增i的值和递减x的值。在本例中,循环开始时x的值为10。每通过一次循环,x的值就递减1。最后,x的值为0,此时循环退出,并执行else子句中的代码,打印出两个变量的值。
    while循环(与本文后面介绍的for循环一样)支持三种附加语句:
        * continue        * break        * pass
    continue和break语句分别用于在while循环中继续下一次循环或中断循环。这两个语句通常放在if语句体中,以便由一个特殊的条件触发continue或break操作。break语句的一个特殊特性是,它完全中断循环,并跳转到循环下面的任一个else子句。
    pass语句什么都不做,它用作一个占位符,即在需要一个语句,但是程序逻辑不需要操作时使用。清单 9中演示了这三种语句。
清单9. 使用continue、break和pass语句
>>> i = 1
>>> while(i >> print i
125
    这个虚构的例子一直循环到变量i大于或等于1,000。在循环中,将i乘以5,然后测试i是否被25整除。记住,您只在表达式为True时执行if语句体。该表达式在当变量i不能被25整除时计算为True。(在 Python表达式中,非零数被计算为布尔值True。)
    循环体中的下一个语句是第二个if语句,它测试变量i是否能被125整除,但是该表达式前面加了一个 not运算符。因此,当变量i的值能被125整除时执行第二个if语句体。此时,break语句导致程序执行中断 while循环,跳转到else子句。
    最后一个if语句永远不会执行,只是用于演示如何在程序中编写pass语句。在后续文章中,将会介绍 pass语句更相关的一些情况。
    通过跟踪程序的逻辑流可以看到,第一次通过循环后,变量i的值变为5。第一个if语句计算为True,因为5不能被25整除。这就会第二次进入while循环,这次变量i变成了25。现在第一个if语句计算为False,因为25能被25整除。第二个和第三个if语句也计算为False,意味着第三次进入循环。这次变量i变成了125,并且第一个if语句计算为False。
    但是第二个if语句计算为True,因为变量i能被125整除(并且not运算符将结果0转换成布尔值 True)。这导致执行break语句,中断循环。else子句永远不被执行,所以直到显式使用print语句之前不会输出任何东西。
for循环
    Python中的for循环很特殊,与Python编程语言中内置的容器数据类型紧密相关。当您在现实生活中有一个容器对象(比如书包)时,您通常想要看它所包含的东西。在编写Python程序时也是这样的。当需要对某件事情做一定的次数时(就像针对容器中的每一项一样),可使用for循环。清单10中的伪代码格式演示了 for循环。
清单10. for循环的伪代码
for item in container:
    # action to repeat for each item in the container
else:
    # action to take once we have finished the loop.
    由于Python容器类型的丰富特性,for循环非常强大。本质上,for循环涉及到一个迭代器(iterator),用于在集合中逐项移动。本系列的下一篇文章将更加详细地介绍for循环,以及如何正确地将它与不同容器类型一起使用。
控制流
    本文介绍了三种Python程序语句:if语句、while循环和for循环。这三种语句通过选择执行哪些语句,或者通过多次执行一组语句,让您可以改变程序流。在后续文章中将大量用到这些语句。复合语句的特性引入了Python程序中的适当缩进特性,这使得Python程序易于读和理解。
参考资料
学习
  • 您可以参阅本文在 developerWorks 全球站点上的
    英文原文

  • 当您有一个可以工作的 Python 解释器时,
    Python Tutorial
    是开始学习该语言的好去处。

  • 本系列的第一篇文章“
    探索 Python,第 1 部分:Python 的内置数值类型
    ”,包含更多关于布尔表达式和 Python 中不同关系和逻辑运算符的信息。

  • 探索 Python,第 2 部分:探索 Python 类型的层次结构,了解对象和容器
    ”讨论了该语言的对象特性,首先介绍内置的简单类型。还介绍并使用了 Python tuple 类,以演示容器类型的概念。

  • 探索 Python,第 3 部分:探索 Python 类型的层次结构,使用字符串
    ”介绍了 string 类,并演示了在 Python 中使用字符串的不同方式。

  • Python 提供了很多有用的特性,其中 list 类是最重要的一个。本系列的
    第 4 部分
    介绍了 list 类,并演示了很多使用它的方式中的一些,以简化困难的编程任务。

  • IBM developerWorks 发表了很多关于 Python 的文章,包括 David Mertz 撰写的高级
    可爱的 Python
    专栏。

  • 访问 developerWorks
    开放源码专区
    ,获得广泛的技术信息、工具和项目更新,以帮助您用开放源码技术进行开发,并与 IBM 产品结合使用。
获得产品和技术
  • 从 Python Web 站点
    下载 Python

  • 从 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 获得评估产品,开始构建应用程序,并部署到 IBM 中间件上。选择 Linux® 或 Windows® 版本的免费
    Software Evaluation Kit (SEK)

  • 利用
    IBM 试用软件
    改革您的下一个开放源码开发项目,该软件可以下载,也可以从 DVD 安装。
讨论

关于作者
    Robert J. Brunner 是国家超级计算应用中心的研究专家,而且是伊利诺伊大学香槟分校的天文学助理教授。他就许多主题出版了几本书,撰写了许多文章和教程。