7. Input and Output 输入与输出

2018-11-05  本文已影响0人  linyk3

There are several ways to present the output of a program; data can be printed in a human-readable form, or written to a file for future use. This chapter will discuss some of the possibilities.
有几种方法可以呈现程序的输出; 数据可以以人类可读的形式打印,或写入文件以供将来使用。 本章将讨论几种可行的做法.

7.1. Fancier Output Formatting 设计输出格式

So far we’ve encountered two ways of writing values: expression statements and the print()function. (A third way is using the write() method of file objects; the standard output file can be referenced as sys.stdout. See the Library Reference for more information on this.)
我们有两种大相径庭的输出值方法:表达式语句和pirnt语句.(第三种方式是使用文件对象的write()方法,标准文件输出可以参考sys.stdout.详细内筒刚才那件库参考手册)

Often you’ll want more control over the formatting of your output than simply printing space-separated values. There are several ways to format output.
可能你经常想要对输出格式做一些比简单的打印空格分隔符更为复杂的控制.这里有几种方式来格式化输出:

>>> year = 2016
>>> event = 'Referendum'
>>> f'Results of the {year} {event}'
'Results of the 2016 Referendum'
>>> yes_votes = 42_572_654
>>> no_votes = 43_132_495
>>> percentage = yes_votes / (yes_votes + no_votes)
>>> '{:-9} YES votes  {:2.2%}'.format(yes_votes, percentage)
' 42572654 YES votes  49.67%'

When you don’t need fancy output but just want a quick display of some variables for debugging purposes, you can convert any value to a string with the repr() or str()functions.
当你不需要花哨的输出但只想快速显示一些变量用于调试时,可以使用[repr()](https://docs.python.org/3 /library/functions.html#repr“repr”)或[str()](https://docs.python.org/3/library/stdtypes.html#str“str”)函数将任何值转换为字符串。

The str() function is meant to return representations of values which are fairly human-readable, while repr() is meant to generate representations which can be read by the interpreter (or will force a SyntaxError if there is no equivalent syntax). For objects which don’t have a particular representation for human consumption, str() will return the same value as repr(). Many values, such as numbers or structures like lists and dictionaries, have the same representation using either function. Strings, in particular, have two distinct representations.
[str()](https://docs.python.org/3/library/stdtypes.html#str“str”)函数用于返回人类可读的值的表现形式,而[repr()](https://docs.python.org/3/library/functions.html#repr“repr”)用于生成可由解释器读取的表示(或如果没有等效语法的话强制执行SyntaxError)。 对于没有特定人类消费代表的对象,str()将返回和repr()相同的值 。 有许多值,例如数字或结构(如列表和字典),使用其中任一函数都具有相同的表示。 但特别的是字符串有两个不同的表示。

Some examples:
一些例子:

>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'
>>> repr(s)
"'Hello, world.'"
>>> str(1/7)
'0.14285714285714285'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
>>> print(s)
The value of x is 32.5, and y is 40000...
>>> # The repr() of a string adds string quotes and backslashes:
... hello = 'hello, world\n'
>>> hellos = repr(hello)
>>> print(hellos)
'hello, world\n'
>>> # The argument to repr() may be any Python object:
... repr((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"

The string module contains a Template class that offers yet another way to substitute values into strings, using placeholders like $x and replacing them with values from a dictionary, but offers much less control of the formatting.
string字符串模块包含一个Template类,它提供了另一种将值替换为字符串的方法,使用$x等占位符并用字典中的值替换它们,但对格式的控制要少得多。

7.1.1. Formatted String Literals 格式化字符串文字

Formatted string literals (also called f-strings for short) let you include the value of Python expressions inside a string by prefixing the string with f or F and writing expressions as{expression}.
格式化的字符串文字(也简称为f-strings)允许您通过在字符串前加上f或F并将表达式写为{expression}来在字符串中包含Python表达式的值。

An optional format specifier can follow the expression. This allows greater control over how the value is formatted. The following example rounds pi to three places after the decimal:
可选的格式说明符可以跟在表达式后面。 这样可以更好地控制值的格式化方式。 以下示例将pi舍入到小数点后的三个位置:

>>> import math
>>> print(f'The value of pi is approximately {math.pi:.3f}.')
The value of pi is approximately 3.142.

Passing an integer after the ':' will cause that field to be a minimum number of characters wide. This is useful for making columns line up.
在':'之后传递一个整数将导致该字段为最小字符数。 这对于使列排列很有用。

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
...     print(f'{name:10} ==> {phone:10d}')
...
Sjoerd     ==>       4127
Jack       ==>       4098
Dcab       ==>       7678

Other modifiers can be used to convert the value before it is formatted. '!a' applies ascii(), '!s' applies str(), and '!r' applies repr():
其他修饰符可用于在格式化之前转换值。 '!a' 表示 ascii(),'!s' 表示 str(),'!r' 表示
repr().

>>> animals = 'eels'
>>> print(f'My hovercraft is full of {animals}.')
My hovercraft is full of eels.
>>> print(f'My hovercraft is full of {animals!r}.')
My hovercraft is full of 'eels'.

For a reference on these format specifications, see the reference guide for the Format Specification Mini-Language.
有关这些格式规范的参考,请参阅格式规范迷你语言的参考指南。

7.1.2. The String format() Method String format() 方法

Basic usage of the str.format() method looks like this:
str.format() 的基本使用方法类似这个:

>>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
We are the knights who say "Ni!"

The brackets and characters within them (called format fields) are replaced with the objects passed into the str.format() method. A number in the brackets can be used to refer to the position of the object passed into the str.format() method.
其中的括号和字符(称为格式字段)将替换为传递给str.format()方法的对象。 括号中的数字可用于表示传递给str.format()方法的对象的位置。

>>> print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
>>> print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam

If keyword arguments are used in the str.format() method, their values are referred to by using the name of the argument.
如果在str.format()方法中使用关键字参数,则使用参数的名称引用它们的值。

>>> print('This {food} is {adjective}.'.format(
...       food='spam', adjective='absolutely horrible'))
This spam is absolutely horrible.

Positional and keyword arguments can be arbitrarily combined:
位置和关键字参数可以任意组合:

>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
                                                       other='Georg'))
The story of Bill, Manfred, and Georg.

If you have a really long format string that you don’t want to split up, it would be nice if you could reference the variables to be formatted by name instead of by position. This can be done by simply passing the dict and using square brackets '[]' to access the keys
如果你有一个非常长的格式字符串,你不想拆分,那么如果你可以引用变量来按名称而不是按位置进行格式化将会很好。 这可以通过简单地传递dict并使用方括号'[]'来访问键来完成

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
...       'Dcab: {0[Dcab]:d}'.format(table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

This could also be done by passing the table as keyword arguments with the ‘’ notation.
这也可以通过将表作为关键字参数传递'
'表示法来完成。

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

This is particularly useful in combination with the built-in function vars(), which returns a dictionary containing all local variables.
这与内置函数vars()结合使用时特别有用,它返回包含所有局部变量的字典。

As an example, the following lines produce a tidily-aligned set of columns giving integers and their squares and cubes:
例如,以下行生成一组整齐对齐的列,给出整数及其正方形和立方体:

>>> for x in range(1, 11):
...     print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

For a complete overview of string formatting with str.format(), see Format String Syntax.
有关使用str.format()的字符串格式的完整概述,请参阅格式字符串语法。

7.1.3. Manual String Formatting 手动字符串格式

Here’s the same table of squares and cubes, formatted manually:
这是同一个正方形和立方体表,手动格式化:

>>> for x in range(1, 11):
...     print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
...     # Note use of 'end' on previous line
...     print(repr(x*x*x).rjust(4))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

(Note that the one space between each column was added by the way print() works: it always adds spaces between its arguments.)
(请注意,每列之间的一个空格是通过print()的工作方式添加的:它总是在其参数之间添加空格。)

The str.rjust() method of string objects right-justifies a string in a field of a given width by padding it with spaces on the left. There are similar methods str.ljust() and str.center(). These methods do not write anything, they just return a new string. If the input string is too long, they don’t truncate it, but return it unchanged; this will mess up your column lay-out but that’s usually better than the alternative, which would be lying about a value. (If you really want truncation you can always add a slice operation, as in x.ljust(n)[:n].)
字符串对象的str.rjust()方法通过在左侧填充空格来对给定宽度的字段中的字符串进行右对齐。 str.ljust() 和str.center() 有类似的方法。 这些方法不会写任何东西,它们只返回一个新字符串。 如果输入字符串太长,它们不会截断它,但会保持不变; 这会弄乱你的列布局,但这通常比替代方案更好,这可能是一个值.(如果你真的想要截断,你可以随时添加切片操作,如x.ljust(n)[:n]。)

There is another method, str.zfill(), which pads a numeric string on the left with zeros. It understands about plus and minus signs:
还有另一种方法str.zfill(),用零填充左边的数字字符串。 它能够分清正负号:

>>> '12'.zfill(5)
'00012'
>>> '-3.14'.zfill(7)
'-003.14'
>>> '3.14159265359'.zfill(5)
'3.14159265359'

7.1.4. Old string formatting 旧的字符串格式

The % operator can also be used for string formatting. It interprets the left argument much like a sprintf()-style format string to be applied to the right argument, and returns the string resulting from this formatting operation. For example:
运算符也可用于字符串格式化。 它将左参数解释为类似于应用于右参数的sprintf()样式格式字符串,并返回由此格式化操作产生的字符串。 例如:

>>> import math
>>> print('The value of pi is approximately %5.3f.' % math.pi)
The value of pi is approximately 3.142.

More information can be found in the printf-style String Formatting section.
可以在printf样式的字符串格式部分中找到更多信息。

7.2. Reading and Writing Files 读写文件

open() returns a file object, and is most commonly used with two arguments: open(filename,mode).
open() 返回一个文件对象,最常用的有两个参数:open(filename,mode).

>>> f = open('workfile', 'w')

The first argument is a string containing the filename. The second argument is another string containing a few characters describing the way in which the file will be used. mode can be 'r' when the file will only be read, 'w' for only writing (an existing file with the same name will be erased), and 'a' opens the file for appending; any data written to the file is automatically added to the end. 'r+' opens the file for both reading and writing. The modeargument is optional; 'r' will be assumed if it’s omitted.
第一个参数是包含文件名的字符串。 第二个参数是另一个字符串,其中包含一些描述文件使用方式的字符。 当只能读取文件时,模式可以是'r',仅写入'w'(将删除具有相同名称的现有文件),'a'打开文件进行追加; 写入文件的任何数据都会自动添加到最后。 'r +'打开文件进行读写。 mode参数是可选的; 如果省略,则会假设'r'。

Normally, files are opened in text mode, that means, you read and write strings from and to the file, which are encoded in a specific encoding. If encoding is not specified, the default is platform dependent (see open()). 'b' appended to the mode opens the file in binary mode: now the data is read and written in the form of bytes objects. This mode should be used for all files that don’t contain text.
通常,文件以文本模式打开,这意味着您从文件读取和写入文件,这些文件以特定编码进行编码。 如果未指定编码,则默认值与平台相关(请参阅open())。 附加到模式的'b'以二进制模式打开文件: 现在以bytes对象的形式读取和写入数据。 此模式应用于所有不包含文本的文件。

In text mode, the default when reading is to convert platform-specific line endings (\n on Unix, \r\n on Windows) to just \n. When writing in text mode, the default is to convert occurrences of \n back to platform-specific line endings. This behind-the-scenes modification to file data is fine for text files, but will corrupt binary data like that in JPEG or EXE files. Be very careful to use binary mode when reading and writing such files.
在文本模式下,读取时的默认值是将平台特定的行结尾(在Unix上为\n,在Windows上为\r\n)转换为\n。 在文本模式下写入时,默认设置是将\n的出现次数转换回平台特定的行结尾。 对文件数据的这种幕后修改对于文本文件来说很好,但会损坏像JPEG或EXE文件中的二进制数据。 在读取和写入此类文件时要非常小心地使用二进制模式。

It is good practice to use the with keyword when dealing with file objects. The advantage is that the file is properly closed after its suite finishes, even if an exception is raised at some point. Using with is also much shorter than writing equivalent try-finally blocks:
在处理文件对象时,最好使用with关键字。 优点是文件套件完成后能够正确关闭,即使在某个时刻引发了异常。 使用with也比编写等效的try-finally块短得多:

>>> with open('workfile') as f:
...     read_data = f.read()
>>> f.closed
True

If you’re not using the with keyword, then you should call f.close() to close the file and immediately free up any system resources used by it. If you don’t explicitly close a file, Python’s garbage collector will eventually destroy the object and close the open file for you, but the file may stay open for a while. Another risk is that different Python implementations will do this clean-up at different times.
如果您没有使用with关键字,那么您应该调用f.close()来关闭该文件并立即释放它使用的所有系统资源。 如果您没有显式关闭文件,Python的垃圾收集器最终将销毁该对象并为您关闭打开的文件,但该文件可能会保持打开状态一段时间。 另一个风险是不同的Python实现将在不同的时间进行清理。

After a file object is closed, either by a with statement or by calling f.close(), attempts to use the file object will automatically fail.
通过with语句或通过调用f.close()关闭文件对象后,尝试使用该文件对象将自动失败。

>>> f.close()
>>> f.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.

7.2.1. Methods of File Objects 文件对象的方法

The rest of the examples in this section will assume that a file object called f has already been created.
本节中的其余示例将假定已创建名为f的文件对象

To read a file’s contents, call f.read(size), which reads some quantity of data and returns it as a string (in text mode) or bytes object (in binary mode). size is an optional numeric argument. When size is omitted or negative, the entire contents of the file will be read and returned; it’s your problem if the file is twice as large as your machine’s memory. Otherwise, at most size bytes are read and returned. If the end of the file has been reached, f.read()will return an empty string ('').
要读取文件的内容,请调用f.read(size),它读取一些数据并将其作为字符串(在文本模式下)或字节对象(在二进制模式下)返回。 * size 是可选的数字参数。当 size 被省略或为负时,将读取并返回文件的全部内容;如果文件的大小是机器内存的两倍,那么这就是你的问题。否则,最多 size *字节被读取并返回。如果到达文件末尾,f.read()将返回一个空字符串('')。

>>> f.read()
'This is the entire file.\n'
>>> f.read()
''

f.readline() reads a single line from the file; a newline character (\n) is left at the end of the string, and is only omitted on the last line of the file if the file doesn’t end in a newline. This makes the return value unambiguous; if f.readline() returns an empty string, the end of the file has been reached, while a blank line is represented by '\n', a string containing only a single newline.
f.readline()从文件中读取一行;换行符(\n)留在字符串的末尾,如果文件没有以换行符结尾,则只在文件的最后一行省略。这使得返回值明确无误;如果f.readline()返回一个空字符串,则到达文件的末尾,而空行由''\n'`表示,该字符串只包含一个换行符。

>>> f.readline()
'This is the first line of the file.\n'
>>> f.readline()
'Second line of the file\n'
>>> f.readline()
''

For reading lines from a file, you can loop over the file object. This is memory efficient, fast, and leads to simple code:
要从文件中读取行,可以循环遍历文件对象。这是内存高效,快速,并导致简单的代码:

>>> for line in f:
...     print(line, end='')
...
This is the first line of the file.
Second line of the file

If you want to read all the lines of a file in a list you can also use list(f) or f.readlines().
如果要读取列表中文件的所有行,也可以使用list(f)或f.readlines()`。

f.write(string) writes the contents of string to the file, returning the number of characters written.
f.write(string)将* string *的内容写入文件,返回写入的字符数。

>>> f.write('This is a test\n')
15

Other types of objects need to be converted – either to a string (in text mode) or a bytes object (in binary mode) – before writing them:
在编写之前,需要将其他类型的对象转换为字符串(在文本模式下)或字节对象(在二进制模式下):

>>> value = ('the answer', 42)
>>> s = str(value)  # convert the tuple to string
>>> f.write(s)
18

f.tell() returns an integer giving the file object’s current position in the file represented as number of bytes from the beginning of the file when in binary mode and an opaque number when in text mode.
f.tell()返回一个整数,给出文件对象在文件中的当前位置,表示为二进制模式下文件开头的字节数和文本模式下的不确定数。

To change the file object’s position, use f.seek(offset, from_what). The position is computed from adding offset to a reference point; the reference point is selected by the from_what argument. A from_what value of 0 measures from the beginning of the file, 1 uses the current file position, and 2 uses the end of the file as the reference point. from_what can be omitted and defaults to 0, using the beginning of the file as the reference point.
要更改文件对象的位置,请使用f.seek(offset,from_what)。通过将* offset 添加到参考点来计算位置;参数点由 from_what 参数选择。当 from_what *值为0,表示从文件开头开始,1使用当前文件位置,2使用文件末尾作为参考点。 * from_what *可以省略,默认为0,使用文件的开头作为参考点。

>>> f = open('workfile', 'rb+')
>>> f.write(b'0123456789abcdef')
16
>>> f.seek(5)      # Go to the 6th byte in the file
5
>>> f.read(1)
b'5'
>>> f.seek(-3, 2)  # Go to the 3rd byte before the end
13
>>> f.read(1)
b'd'

In text files (those opened without a b in the mode string), only seeks relative to the beginning of the file are allowed (the exception being seeking to the very file end with seek(0, 2)) and the only valid offset values are those returned from the f.tell(), or zero. Any other offset value produces undefined behaviour.
在文本文件中(那些在模式字符串中没有“b”打开的文件),只允许相对于文件开头的搜索(一个例外是用seek(0,2)来寻找文件末尾)。唯一有效的* offset 值是从f.tell()返回的值,或者为零。任何其他 offset *值都会产生未定义的行为。

File objects have some additional methods, such as isatty() and truncate() which are less frequently used; consult the Library Reference for a complete guide to file objects.
文件对象有一些额外的方法,比如isatty()truncate(),它们使用频率较低;有关文件对象的完整指南,请参阅“库参考”。

7.2.2. Saving structured data with json 用json存储结构化数据

Strings can easily be written to and read from a file. Numbers take a bit more effort, since the read() method only returns strings, which will have to be passed to a function like int(), which takes a string like '123' and returns its numeric value 123. When you want to save more complex data types like nested lists and dictionaries, parsing and serializing by hand becomes complicated.
可以轻松地将字符串写入文件并从文件中读取。数字需要更多的努力,因为read()方法只返回字符串,这些字符串必须传递给类似int()的函数,它接受一个像''123'的字符串并返回其数值123。当您想要保存更复杂的数据类型(如嵌套列表和字典)时,手动解析和序列化变得复杂。

Rather than having users constantly writing and debugging code to save complicated data types to files, Python allows you to use the popular data interchange format called JSON (JavaScript Object Notation). The standard module called json can take Python data hierarchies, and convert them to string representations; this process is called serializing. Reconstructing the data from the string representation is called deserializing. Between serializing and deserializing, the string representing the object may have been stored in a file or data, or sent over a network connection to some distant machine.
Python允许您使用称为JSON(JavaScript Object Notation -- JavaScript对象表示法)的流行数据交换格式,而不是让用户不断编写和调试代码以将复杂的数据类型保存到文件中。名为json的标准模块可以采用Python数据层次结构,以及将它们转换为字符串表示;这个过程叫做serializing 序列号。从字符串重构数据类型称为反序列化。在序列化和反序列化之间,表示对象的字符串可能已存储在文件或数据中,或通过网络连接发送到某个远程机器。

Note:The JSON format is commonly used by modern applications to allow for data exchange. Many programmers are already familiar with it, which makes it a good choice for interoperability.
注意:现代应用程序通常使用JSON格式来进行数据交换。许多程序员已经熟悉它,这使其成为互操作性的良好选择。

If you have an object x, you can view its JSON string representation with a simple line of code:
如果你有一个对象x,你可以用一行简单的代码查看它的JSON字符串表示:

>>> import json
>>> json.dumps([1, 'simple', 'list'])
'[1, "simple", "list"]'

Another variant of the dumps() function, called dump(), simply serializes the object to a text file. So if f is a text file object opened for writing, we can do this:
dumps()函数的另一个变体叫做dump(),它只是将对象序列化为文本文件。因此,如果f是为写入而打开的文本文件对象,我们可以这样做:

json.dump(x, f)

To decode the object again, if f is a text file object which has been opened for reading:
要再次解码对象,如果f是已打开以供阅读的文本文件对象:

x = json.load(f)

This simple serialization technique can handle lists and dictionaries, but serializing arbitrary class instances in JSON requires a bit of extra effort. The reference for the json module contains an explanation of this.
这种简单的序列化技术可以处理列表和字典,但是在JSON中序列化任意类实例需要额外的努力。 json模块的引用包含对此的解释。
See also pickle - the pickle module
另见pickle模块

Contrary to JSON, pickle is a protocol which allows the serialization of arbitrarily complex Python objects. As such, it is specific to Python and cannot be used to communicate with applications written in other languages. It is also insecure by default: deserializing pickle data coming from an untrusted source can execute arbitrary code, if the data was crafted by a skilled attacker.
与JSON相反,pickle是一种允许对任意复杂Python对象进行序列化的协议。因此,它特定于Python,不能用于与其他语言编写的应用程序通信。默认情况下它也是不安全的:如果数据是由熟练的攻击者精心设计的,则反序列化来自不受信任来源的pickle数据可以执行任意代码.

上一篇下一篇

猜你喜欢

热点阅读