核心:输入与输出 =================== 有些时候你的程序会与用户产生交互。举个例子,你会希望获取用户的输入内容,并向用户打印出一些返回的结果。我们可以分别通过 ``input()`` 函数与 ``print`` 函数来实现这一需求。 对于输入,我们还可以使用 ``str`` (String,字符串)类的各种方法。例如,你可以使用 ``rjust`` 方法来获得一个右对齐到指定宽度的字符串。你可以查看 ``help(str)`` 来了解更多细节。 另一个常见的输入输出类型是处理文件。创建、读取与写入文件对于很多程序来说是必不可少的功能,而我们将在本章探讨这一方面。 用户输入内容 ------------ 将以下程序保存为 ``io_input.py``\ : .. code:: python def reverse(text): return text[::-1] def is_palindrome(text): return text == reverse(text) something = input("Enter text: ") if is_palindrome(something): print("Yes, it is a palindrome") else: print("No, it is not a palindrome") 输出: .. code:: console $ python3 io_input.py Enter text: sir No, it is not a palindrome $ python3 io_input.py Enter text: madam Yes, it is a palindrome $ python3 io_input.py Enter text: racecar Yes, it is a palindrome **它是如何工作的** 我们使用切片功能翻转文本。我们已经了解了我们可以通过使用 ``seq[a:b]`` 来从位置 ``a`` 开始到位置 ``b`` 结束来\ :doc:`对序列进行切片 <./data_structures>` \ 。我们同样可以提供第三个参数来确定切片的 *步长(Step)* 。默认的步长为 ``1``\ ,它会返回一份连续的文本。如果给定一个负数步长,如 ``-1``\ ,将返回翻转过的文本。 ``input()`` 函数可以接受一个字符串作为参数,并将其展示给用户。尔后它将等待用户输入内容或敲击返回键。一旦用户输入了某些内容并敲下返回键,\ ``input()`` 函数将返回用户输入的文本。 我们获得文本并将其进行翻转。如果原文本与翻转后的文本相同,则判断这一文本是\ `回文 `__\ 。 以下是`` input``方法的例子. 注意:python2中的 raw_input_A()方法已经不能在Python3中使用. .. code:: python >>> input_A = input("Input: ") Input: abc >>> input_B = input("Input: ") Input: 123 >>> type(input_B) 练习 ~~~~ 要想检查文本是否属于回文需要忽略其中的标点、空格与大小写。例如,“Rise to vote, sir.”是一段回文文本,但是我们现有的程序不会这么认为。你可以改进上面的程序以使它能够识别这段回文吗? 如果你需要一些提示,那么可以考虑使用一个元组(你可以在这里找到一份列出_所有\_\ `标点符号 `__\ 的列表)来保存所有需要禁用的字符,如forbidden = (``!``, ``?``, ``.``, …)。然后使用成员资格测试来确定一个字符是否应该被移除。 操作文件:读取与写入 -------------------- 由于这里读取,写入需要伴随文件操作,所以我们一并说明. file对象是和string、float一样的内置对象类型,可由open命令创建. 你可以通过创建一个属于 ``file`` 类的对象并适当使用它的 ``read``\ 、\ ``readline``\ 、\ ``write`` 方法来打开或使用文件,并对它们进行读取或写入。读取或写入文件的能力取决于你指定以何种方式打开文件。最后,当你完成了文件,你可以调用 ``close`` 方法来告诉 Python 我们已经完成了对该文件的使用。 示例(保存为 ``io_using_file.py``\ ): .. code:: python poem = '''\ Programming is fun When the work is done if you wanna make your work also fun: use Python! ''' f = open('poem.txt', 'w') # 打开文件以编辑('w'riting) f.write(poem) # 向文件中写入文本 f.close() # 关闭文件 # 如果没有特别指定, # 将假定启用默认的阅读('r'ead)模式 f = open('poem.txt') while True: line = f.readline() # 零长度指示 if len(line) == 0: break # 每行(`line`)的末尾 # 都已经有了换行符 # 因为它是从一个文件中进行读取的 print(line, end='') f.close() # 关闭文件 输出: .. code:: text $ python3 io_using_file.py Programming is fun When the work is done if you wanna make your work also fun: use Python! 以下是另外几个文本读取的例子: •完整版文件操作,其中r 只读、w 写、rw 读写,rb二进制读 .. code:: python f=open('filename','r') text=f.read() f.close() •简略版文件操作: .. code:: python text=open('filename','r').readlines() text=open('filename','r').read().split('\n') **它是如何工作的** 首先,我们使用内置的 ``open`` 函数并指定文件名以及我们所希望使用的打开模式来打开一个文件。打开模式可以是阅读模式(\ ``'r'``\ ),写入模式(\ ``'w'``\ )和追加模式(\ ``'a'``\ )。我们还可以选择是通过文本模式(\ ``'t'``\ )还是二进制模式(\ ``'b'``\ )来读取、写入或追加文本。实际上还有其它更多的模式可用,\ ``help(open)`` 会给你有关它们的更多细节。在默认情况下,\ ``open()`` 会将文件视作文本(\ **t**\ ext)文件,并以阅读(\ **r**\ ead)模式打开它。 在我们的案例中,我们首先采用写入模式打开文件并使用文件对象的 ``write`` 方法来写入文件,并在最后通过 ``close`` 关闭文件。 接下来,我们重新在阅读模式下打开同一个文件。我们不需要特别指定某种模式,因为“阅读文本文件”是默认的。 为了完成不同的读取任务,文件对象提供了三个"读"方法: ``read()`` 读取整个文件,将内容存入字符串变量; ``readline()`` 每次只读取一行; ``.readlines()`` 将文件内容分析成一个行的列表我们在循环中使用. 当然,如果你不想使用 ``.readlines`` 读取整个文件,那么可以使用循环加上 ``readline`` 方法来读取文件的每一行。这一方法将会一串完整的行,其中在行末尾还包含了换行符。当一个空字符串返回时,它表示我们已经到达了文件末尾,并且通过 ``break`` 退出循环。 最后,我们通过 ``close`` 关闭了文件。 现在,你可以检查 ``poem.txt`` 文件的内容来确认程序确实对该文件进行了写入与读取操作。 Pickle ------ Python 提供了一个叫作 ``Pickle`` 的标准模块,通过它你可以将 *任何* 纯 Python对象存储到一个文件中,并在稍后将其取回。这叫作 *持久地(Persistently)* 存储对象。 案例(保存为 ``io_pickle.py``\ ): .. code:: python import pickle # 我们存储相关对象的文件的名称 shoplistfile = 'shoplist.data' # 需要购买的物品清单 shoplist = ['apple', 'mango', 'carrot'] # 准备写入文件 f = open(shoplistfile, 'wb') # 转储对象至文件 pickle.dump(shoplist, f) f.close() # 清除 shoplist 变量 del shoplist # 重新打开存储文件 f = open(shoplistfile, 'rb') # 从文件中载入对象 storedlist = pickle.load(f) print(storedlist) 输出: .. code:: console $ python io_pickle.py ['apple', 'mango', 'carrot'] **它是如何工作的** 要想将一个对象存储到一个文件中,我们首先需要通过 ``open`` 以写入(\ **w**\ rite)二进制(\ **b**\ inary)模式打开文件,然后调用 ``pickle`` 模块的 ``dump`` 函数。这一过程被称作 *封装(Pickling)* 。 接着,我们通过 ``pickle`` 模块的 ``load`` 函数接收返回的对象。这个过程被称作 *拆封(Unpickling)*。 编码方式 -------- 日常生活中,我们不可能只用到英文。所以针对其他语言及字符集有新的标准来规范,以下是一些例子: * *ASCII* 1967 年由美国国家标准学会(ANSI)公布的单字节编码系统,主要包括26 个拉丁字母、阿拉伯数字和英式标点。 * *GB2312* 1981 年由国家标准总局发布的双字节编码字符集。包含汉字6763 个和非汉字图形字符682 个。 * *Big5* 1984 年由台湾厂商为当时五大中文软件所设计的中文内码,共收录13,060 个中文字,长期通行于台湾、香港。 * *GBK* 1995 年颁布的《汉字编码扩展规范》(GBK)支持中、日、韩(CJK)汉字共计20902 字。兼容GB2312。 * *Unicode* 1991 年出现的统一编码字符集,可容纳100 万个字符。这个字符集包括UTF-8、UTF-16、UTF-32多种编码方式。与ASCII 兼容,原有处理ASCII 字符的软件可以继续使用。 Unicode ------- 截止到现在,当我们编写或使用字符串、读取或写入某一文件时,我们用到的只是简单的英语字符。 注意:如果你正在使用 Python 2,我们又希望能够读写其它非英语语言,我们需要使用 ``unicode`` 类型,它全都以字母 ``u`` 开头,例如 ``u"hello world"``\ 。 .. code:: python >>> "hello world" 'hello world' >>> type("hello world") >>> u"hello world" 'hello world' >>> type(u"hello world") 当我们阅读或写入某一文件或当我们希望与互联网上的其它计算机通信时,我们需要将我们的 Unicode 字符串转换至一个能够被发送和接收的格式,这个格式叫作“UTF-8”。我们可以在这一格式下进行读取与写入,只需使用一个简单的关键字参数到我们的标准 ``open`` 函数中: .. code:: python # encoding=utf-8 import io f = io.open("abc.txt", "wt", encoding="utf-8") f.write(u"Imagine non-English language here") f.close() text = io.open("abc.txt", encoding="utf-8").read() print(text) **它是如何工作的** 现在你可以忽略 ``import`` 语句, 我们会在\ :doc:`模块章节 <./modules>`\ 章节探讨有关它的更多细节。 每当我们诸如上面那番使用 Unicode 字面量编写一款程序时,我们必须确保 Python 程序已经被告知我们使用的是 UTF-8,因此我们必须将 ``# encoding=utf-8`` 这一注释放置在我们程序的顶端。 我们使用 ``io.open`` 并提供了“编码(Encoding)”与“解码(Decoding)”参数来告诉 Python 我们正在使用 Unicode。 你可以阅读以下文章来了解有关这一话题的更多内容: - `“The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets” `__ - `Python Unicode Howto `__ - `Pragmatic Unicode talk by Nat Batchelder `__ 总结 ---- 这章我们讨论了有关输入和输出的多种类型,这些内容有关文件处理, pickle 模块,Unicode及其他编码。