《Python 3程序开发指南(第2版•修订版)》——1.3 实例

1.3 实例

在前面的几节中,我们介绍了足以编写实际程序的Python知识与技术。在这一节中,我们将介绍两个完整的程序,这些程序只涉及前面已经讲过的知识。一方面是为了展示前面所学的知识可以完成什么任务,一方面也是为了巩固前面所学的知识。

在后面的章节中,我们会逐渐学习更多的Python知识与库模块,以便于编写出比这里展示的程序更精确与更强壮的程序——但是首先我们必须先掌握这些基础知识。

1.3.1 bigdigits.py

这里给出的第一个程序非常短小,尽管该程序也有一些微妙之处,包括列表组成的列表等。这个程序的功能是:在命令行中提供一个数值,之后该程序会使用“大”数字向控制台输出该数值。

在大量用户共享高速行式打印机的站点上,使用这种技术是很常见的做法,即为每个用户的打印作业打印一个引导页,使其包含用户名与其他有助于区分不同用户的详细资料。

我们分3个部分查看该程序的代码:import部分;创建列表(其中存放程序要使用的数据)部分;处理部分本身。不过,我们首先看一下运行的效果:

bigdigits.py 41072819
                                 *
                                       *
                                         *
                                       *
                                       *
                                            
                                  

我们没有展示控制台提示符(或UNIX用户的./),而是将这些内容默认为已经存在的。

import sys

由于我们必须从命令行中读入一个参数(也就是要输出的数值),我们需要访问sys.argv列表,因此我们从导入sys模块开始。

我们以字符串列表的形式展示每个数值,比如,下面展示的是zreo:

Zero = ["  *  ",
        "     ",
        "     ",
        "     ",
        "     ",
        "     ",
        "  *  "]

这里需要注意的一个细节是,Zero的字符串列表表示形式跨越了多个行。通常,Python语句只占用一行,但是也可以跨越多行,比如使用圆括号包含的表达式、列表、集合、字典字面值、函数调用参数列表以及多行语句(除最后一行之外,每行的行终结符都使用反斜线进行引导并转义处理)。上面的这些Python语句可以跨越任意多的行,代码缩排也并不会影响第二行以及后续的行。

用于表示数值的每个列表包含7个字符串,在对同一个数值的表示中,这些字符串是等宽的,而表示不同数值的字符串宽度不同。表示其他数值的列表在形式上与上面给出的Zero类似。下面给出的几个表示主要是出于紧致性考虑,因而不那么形象和清晰:

One = ["  ", " ", "  ", "  ", "  ", "  ", ""]
Two = ["  ", "   ", "   ", "   ",  "    ", "    ", "*"]
# ...
Nine = [" ", "  ", "  ", " ", "   ", "    ", "   *"]

我们还需要的最后一个数据结构是所有数字列表组成的列表:

Digits = [Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine]

我们也可以直接创建Digits列表,而不必创建额外的变量,例如:

Digits = [
    ["  *  ", "     ", "     ", "     ", "     ",
     "     ", "  *  "], # Zero
    ["  ", " ", "  ", "  ", "  ", "  ", ""], # One
    # ...
    [" ", "   ", "   ", " ", "    ", "    ",
     "    *"] # Nine
    ]

我们更愿意使用单独的变量来分别表示每个数值,一方面是为了便于理解,另一方面是因为使用变量来表示看起来更整洁。

下面一起展示了余下的代码部分,以便你在阅读其后的解释之前自己可以设想其工作方式。

try:
    digits = sys.argv[1]
    row = 0
    while row < 7:
        line = ""
        column = 0
        while column < len(digits):
            number = int(digits[column])
            digit = Digits[number]
            line += digit[row] + " "
            column += 1
        print(line)
        row += 1
except IndexError:
    print("usage: bigdigits.py <number>")
except ValueError as err:
    print(err, "in", digits)

上面这段代码整体包含在一个异常处理模块中,并可以捕获两个异常。该段代码首先取回程序的命令行参数,与所有Python列表类似,sys.argv列表的索引项是从0开始的,索引位置为0的数据项是调用的程序名,因此,在一个运行的程序中,该列表总是至少包含一项。如果没有给定参数,我们会在一个单数据项的列表中尝试访问第二个数据项,并导致产生一个IndexError异常。如果发生这种情况,控制流立即转向相应的异常处理块,这里只是简单地打印出程序的用法。在Try块结束后,程序继续执行,但是由于已经没有更多的代码,因此程序只是简单地退出。

如果没有发生IndexError异常,那么digits字符串会存放命令行参数,如果一切正常,就应该是一个数字字符序列。(记住,要素2中讲过,标识符对大小写敏感,因此,digits与Digits是不同的。)每个大数都使用7个字符串表示,为正确地输出数值,我们必须首先输出每个数字的顶行,之后是下一行,依此类推,直至输出所有的7行。我们使用一个while循环,以便逐行迭代。我们也可以采用另一种方法:for row in (0, 1, 2, 3, 4, 5, 6):,后面我们还将看到一种更好的、使用内置的range()函数的方法。

我们使用line字符串来存放所有数字的行字符串,之后根据列进行循环,也就是说,根据命令行参数中每个相继的字符进行循环。我们使用digits[column]取回每个字符,并将数字转换为称为number的整数。如果转换失败,就会产生一个ValueError异常,控制流立即转向相应的异常处理模块。这种情况下,我们将打印出错误消息,并在try块之后恢复控制。与前面类似,由于没有其他代码等待执行,因此程序只是简单地退出。

如果转换成功,我们就使用number作为索引来存取digits列表,并从其中抽取字符串列表digit,之后我们从这一列表中将相应的字符串添加到我们正在构建的行,并添加两个空格,以便在数字之间添加水平分隔。

内部的while循环每次结束时,我们会打印出刚构建好的行。理解这一程序的关键之处在于我们将每个数字的row字符串添加到当前row的行。读者可以尝试运行该程序,以便理解其运作方式。在章后练习中,我们将再次讲到该程序,以便对其输出进行稍许改变。

1.3.2 generate_grid.py

我们频繁面临的需求是测试数据的生成。由于不同场景下测试数据变化巨大,因此无法找到一个满足所有测试数据需求的通用程序。由于编写与修改Python程序都很容易, Python经常被用于生成测试数据。在这一小节中,我们将创建一个生成随机整数组成的网格的程序,用户可以规定需要多少行、多少列,以及整数所在的区域。我们首先从一个运行实例开始:

generate_grid.py
rows: 4x
invalid literal for int() with base 10: '4x'
rows: 4
columns: 7
minimum (or Enter for 0): -100
maximum (or Enter for 1000):
       554       720       550       217       810       649        912
       -24       908       742       -65       -74        724        825
       711       968       824       505       741        55        723
       180       -60       794       173       487         4        -35

该程序以交互式的方式运行,最开始在输入行数时,由于输入的行数有误,导致程序打印一条错误消息,并要求用户重新输入行数。对于maximum,我们只是简单地按Enter键,以便接受默认值。

我们将分别解读该程序的4个部分:import、函数get_int()的定义(此函数比要素8中展示的类似函数更复杂)、用户交互以便获取要使用的值、处理过程本身。

import random

我们需要random模块,以便访问其中的random.randinit()函数。

def get_int(msg, minimum, default):
    while True:
        try:
            line = input(msg)
            if not line and default is not None:
                return default
            i = int(line)
            if i < minimum:
                print("must be >=", minimum)
            else:
                return i
        except ValueError as err:
            print(err)

这一函数需要3个参数:一个消息字符串、一个最小值、一个默认值。如果用户只是简单地按Enter键,就有两种可能性。如果default为None,也就是说没有给定默认值,那么控制流将转到int()行,在该处转换将失败(因为无法转换为整数),并产生一个ValueError异常;如果default非None,就返回该值。否则,函数将尝试把用户输入的文本转换为整数,如果转换成功,接下来将检查该整数是否至少等于指定的minimum。

因此,该函数的返回总是两种情况,或者是default(用户只是按Enter键),或者是一个有效的整数(大于或等于指定的minimum)。

rows = get_int("rows: ", 1, None)
columns = get_int("columns: ", 1, None)
minimum = get_int("minimum (or Enter for 0): ", -1000000, 0)
default = 1000
if default < minimum:
    default = 2 * minimum
maximum = get_int("maximum (or Enter for " + str(default) + "): ",
                    minimum, default)

通过我们的get_int()函数,可以很容易地获取行数、列数以及用户需要的最小随机数值。对于给定默认值None的行数与列数,也就是没有指定默认值的情况,用户必须输入一个整数。对于minimum,我们提供的默认值为0:对于maximum,我们提供的默认值为1000或minimum的2倍(如果minimum大于或等于1000)。

与前面的例子类似,函数调用参数列表可以跨越任意数量的行数,并且缩排与第二行及后继行无关。

在确定用户需要的具体行数、列数以及随机数的最大值与最小值后,就可以进行具体的随机数生成过程:

row = 0
while row < rows:
    line = ""
    column = 0
    while column < columns:
        i = random.randint(minimum, maximum)
        s = str(i)
        while len(s) < 10:
            s = " " + s
        line += s
        column += 1
    print(line)
    row += 1

为生成随机数网格,我们使用3个while循环,外部循环以行数进行循环,中间循环以列数进行循环,内部循环则以字符进行循环。在中间循环中,我们获取指定范围内的随机数,并将其转换为字符串。内部while循环用于对字符串进行填充(填充数据为空格),以便每个数字都使用10个字符的字符串表示,对每一行,使用字符串line来累积数值,在每一列的数字添加完毕后,就打印出该行表示的数字,至此,第二个程序功能讲解完毕。

Python提供了非常高级的格式化功能,以及对for ... in循环的良好支持能力,因此,bigdigits.py与generate_grid.py这两个程序的更真实的版本会使用for ... in循环,generate_grid.py程序将使用Python的字符串格式化功能,而不是像这里这样不带修饰地使用空格进行填充。但是在本章中,我们将自己约束在使用本章介绍的8个关键要素进行程序设计,并且这8个要素对编写完整而有用的程序也已足够。在接下来的每一章中,我们都将学习Python的一些新特性,因此,随着本书内容的推进,所看到的程序将逐步复杂起来。

时间: 2024-11-02 09:34:09

《Python 3程序开发指南(第2版•修订版)》——1.3 实例的相关文章

《Python 3程序开发指南(第2版•修订版)》——2.2 Integral类型

2.2 Integral类型 Python提供了两种内置的Integral类型,即int与bool1.整数与布尔型值都是固定的,但由于Python提供了增强的赋值操作符,使得这一约束极少导致实际问题.在布尔表达式中,0与False表示False,其他任意整数与true都表示true.在数字表达式中,True表示1,False表示0.这意味着,有些看起来很怪异的表达式也是有效的.例如,我们可以使用表达式i += True来对整型变量i进行递增操作,当然,最自然的方法还是i+=1. 2.2.1 整数

《Python 3程序开发指南(第2版•修订版)》——第1章 过程型程序设计快速入门 1.1 创建并运行Python程序

第1章 过程型程序设计快速入门 本章提供了足以开始编写Python程序的信息.如果此时尚未安装Python,强烈建议读者先行安装Python,以便随时进行编程实践,获取实际经验,巩固所学的内容. 本章第1节展示了如何创建并执行Python程序.你可以使用自己最喜欢的普通文本编辑器来编写Python代码,但本节中讨论的IDLE程序设计环境提供的不仅是一个代码编辑器,还提供了很多附加的功能,包括一些有助于测试Python代码.调试Python程序的工具. 第2节介绍了Python的8个关键要素,通过

《Python 3程序开发指南(第2版•修订版)》——7.3 写入与分析XML文件

7.3 写入与分析XML文件 有些程序将其处理的所有数据都使用XML文件格式,还有些其他程序将XML用作一种便利的导入/导出格式.即便程序的主要格式是文本格式或二进制格式,导入与导出XML的能力也是有用的,并且始终是值得考虑的一项功能. Python提供了3种写入XML文件的方法:手动写入XML:创建元素树并使用其write()方法:创建DOM并使用其write()方法.XML文件的读入与分析则有4种方法:人工读入并分析XML(不建议采用这种方法,这里也没有进行讲述--正确处理某些更晦涩和更高级

《Python 3程序开发指南(第2版•修订版)》——2.7 练习

2.7 练习 1.修改程序print_unicode.py,以便用户可以在命令行上输入几个单独的单词,并且只有在Unicode字符名包含用户指定的所有单词时才打印相应列.这意味着,我们可以输入类似于如下的命令: print_unicode_ans.py greek symbol 实现上述要求的一种方法是使用words列表替换word变量(其中存放0.None或字符串).改变代码后,要记得更新使用帮助信息.这一改变需要添加不到10行代码,另外需要对不到10行的代码进行适当修改.文件print_un

《Python 3程序开发指南(第2版•修订版)》——2.3 浮点类型

2.3 浮点类型 Python提供了3种浮点值:内置的float与complex类型,以及来自标准库的decimal.Decimal类型,这3种数据类型都是固定的.float类型存放双精度的浮点数,具体取值范围则依赖于构建Python的C(或C#或Java)编译器,由于精度受限,对其进行相等性比较并不可靠.float类型的数值要使用小数点或使用指数表示,比如,0.0.4..5.7.-2.5.-2e9.8.9e-4等. 计算机使用基数2表示浮点数--这意味着,有些十进制数可以准确表示(比如0.5)

《Python 3程序开发指南(第2版•修订版)》——1.2 Python的关键要素

1.2 Python的关键要素 在本节中,我们将学习Python的8个关键要素,下一节中,我们将展示如何借助这些要素编写实际的小程序.关于本节中讲述的各关键要素,都有更多的内容需要阐述,因此,阅读本节的内容时,有时候你会觉得Python似乎遗失了一些内容,使得很多工作只能以一种冗繁的模式完成,如果使用前向索引或索引表格中的内容,那么你几乎总是可以发现Python具备你需要的特性,并且可以更紧凑的表达方式来完成当前展示的工作方式--还有很多其他内容. 1.2.1 要素#1:数据类型 任何程序语言都

《Python 3程序开发指南(第2版•修订版)》——2.4 字符串

2.4 字符串 字符串是使用固定不变的str数据类型表示的,其中存放Unicode字符序列.str数据类型可以作为函数进行调用,用于创建字符串对象--参数为空时返回一个空字符串,参数为非字符串类型时返回该参数的字符串形式,参数为字符串时返回该字符串的拷贝.str()函数也可以用作一个转换函数,此时要求第一个参数为字符串或可以转换为字符串的其他数据类型,其后跟随至多两个可选的字符串参数,其中一个用于指定要使用的编码格式,另一个用于指定如何处理编码错误. 前面我们注意到,字符串是使用引号创建的,可以

《Python 3程序开发指南(第2版•修订版)》——2.5 实例

2.5 实例 在这一节中,我们将根据本章以及前面一章中所学的知识,提供两个虽小但完整的程序,以助于巩固到此为止所学的Python知识.第一个程序有点偏数学化,但是非常小,大约35行代码.第二个程序是关于文本处理的,并且更具体,其中包含7个函数,大约80行代码. 2.5.1 quadratic.py 二次方程是指形如ax2 + bx + c = 0的方程,其中,a不为0描述的是抛物线.这一方程的根可以由公式 得出,其中,公式的b2-4ac部分称为判别式--如果为正值,那么该方程有两个实根:如果为0

《Python 3程序开发指南(第2版•修订版)》——1.5 练习

1.5 练习 在本书的每一章最后,都有一节练习,设置练习的目的是鼓励读者对Python进行实践,获取实际经验,以助于吸收每章中所学的知识.本节包括的实例与练习既涉及数字处理,也涉及文本处理,以便尽可能满足更多读者的需求.此外,这些实例与练习都有非常小的代码规模,以便于读者将重点和注意力集中于学习与思考,而不是仅仅输入代码.本书的实例中,为每个练习都提供了一个解决方案. 1.bigdigits.py程序的一个变形,不再打印*,而是打印具体的数字.例如: bigdigits_ans.py 71942

《Python 3程序开发指南(第2版•修订版)》——导读

前 言 在应用广泛的各种语言中,Python或许是最容易学习和最好使用的.Python代码很容易阅读和编写,并且非常清晰,而没有什么隐秘的.Python是一种表达能力非常强的语言,这意味着,在设计同样的应用程序时,使用Python进行编码所需要的代码量要远少于使用其他语言(比如C++或Java)的代码量. Python是一种跨平台的语言:一般来说,同样的Python程序可以同时在Windows平台与UNIX类平台(比如Linux.BSD与Mac OS X)上运行--只需要将构成Python程序的