7. Input and Output

7. Input and Output

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.本章将讨论其中的几种方法。

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详细内容参见库参考手册。)

通常你会希望更好地控制输出的格式而不是简单地打印用空格分隔的值。有两种方式格式化你的输出;第一种方式是做所有字符串处理自己;使用字符串切片和串联操作,您可以创建任何你可以想象的布局。The string type has some methods that perform useful operations for padding strings to a given column width; these will be discussed shortly. 第二种方法是使用 str.format() 方法。

The string module contains a Template class which offers yet another way to substitute values into strings.

当然还有一个问题:如何将值转换为字符串?幸运的是,python已经有方法把任何值转换成字符串:使用repr() 或 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()许多值,例如数字或者列表和字典这样的结构,使用这两个函数中的任意一个都具有相同的表示形式。字符串特殊一些,有两种不同的表示形式。

例如:

>>>
>>> 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'))"

这里用两种方法输出平方和立方表:

>>>
>>> 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

>>> 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

(Note that in the first example, one space between each column was added by the way print() works: it always adds spaces between its arguments.)

This example demonstrates the str.rjust() method of string objects, which 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()这些方法不会输出任何内容,它们只返回新的字符串。如果输入的字符串太长,字符串不会被截短,会完整输出。这将会使列不对齐,但是通常这比截短好,截短会导致不知道原值(If you really want truncation you can always add a slice operation, as in x.ljust(n)[:n].)

There is another method, str.zfill(), which pads a numeric string on the left with zeros. 该函数可以正确识别正负号:

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

Basic usage of the str.format() method looks like this:

>>>
>>> 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.

>>>
>>> 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.

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

位置参数和关键字参数可以随意组合:(actually,positional argument follows keyword argument will raise SyntaxError)

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

'!a' (apply ascii()), '!s' (apply str()) and '!r' (apply repr()) can be used to convert the value before it is formatted:

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

An optional ':' and format specifier can follow the field name. 这允许更好地控制值是何种格式。下面的例子将 Pi 转为三位精度。

>>>
>>> import math
>>> print('The value of PI is approximately {0:.3f}.'.format(math.pi))
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. 这在美化表格时很有用。

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

如果你有一个实在是很长的格式字符串但又不想分开写,要是可以按照名字而不是位置引用变量就好了。This can be done by simply passing the dict and using square brackets'[]' to access the keys

>>>
>>> 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

这也可以用 ‘**’ 标志将这个字典以关键字参数的方式传入。

>>>
>>> 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.

For a complete overview of string formatting with str.format(), see Format String Syntax.

7.1.1. Old 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. 例如:

>>>
>>> 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.

7.2. 读写文件

open () 返回一个 文件对象,其最常用的有两个参数︰ 打开 (文件名, 模式)

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

第一个参数是一个含有文件名的字符串。第二个参数也是一个字符串,含有描述如何使用该文件的几个字符。模式 can be 'r' 是只读, 'w' 是写,如果文件已经存在,就清空内容后写入, 'a' 打开文件,内容后添加写入到文件末尾。'r+' 读写双开.模式 参数是可选的, 如果不传,默认'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.

In text mode, the default when reading is to convert platform-specific line endings (\n on Unix, \r\n on Windows) to just \nWhen 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 EXEfiles. 使用二进制模式读写此类文件时要特别小心。

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.

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 是可选的数值参数。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. 否则,至多读取和返回 size 大小的字节数据。If the end of the file has been reached, f.read() will return an empty string ('').

>>>
>>> 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()
'This is the first line of the file.\n'
>>> f.readline()
'Second line of the file\n'
>>> f.readline()
''

你可以循环遍历文件对象来读取文件中的每一行。这是既省内存又非常快的简单代码:

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

如果你想要读取的文件列表中的所有行的数据,你也可以使用 list(f) 或 f.readlines()

f.write(string) 将 字符串 的内容写入到该文件,返回写入的字符数。

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

其他类型的对象,在写入之前则需要转换成 字符串 (在文本模式下) 或 字节对象 (以二进制模式)

>>>
>>> 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.

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 thefrom_what argument. 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 withseek(0, 2)) and the only valid offset values are those returned from the f.tell(), or zero. 其它任何偏移 值都会产生未定义的行为。

When you’re done with a file, call f.close() to close it and free up any system resources taken up by the open file. After calling f.close(), attempts to use the file object will automatically fail.

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

It is good practice to use the with keyword when dealing with file objects. 这样做的好处在于文件用完后会自动关闭,即使过程中发生异常也没关系。It is also much shorter than writing equivalent try-finally blocks:

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

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.

7.2.2. Saving structured data with json

从文件中读写字符串很容易。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. 当你想要保存更为复杂的数据类型,例如嵌套的列表和字典,手工解析和序列化它们将变得更复杂。

好在用户不是非得自己编写和调试保存复杂数据类型的代码,Python 允许你使用常用的数据交换格式JSON(JavaScript Object Notation)The standard module called jsoncan take Python data hierarchies, and convert them to string representations; this process is called serializing从字符串表示形式重新构建数据结构称为反序列化序列化和反序列化的过程中,表示该对象的字符串可以存储在文件或数据中,也可以通过网络连接传送给远程的机器。

注意

JSON 格式经常用于现代应用程序中进行数据交换。许多程序员都已经熟悉它了,使它成为相互协作的一个不错的选择。

If you have an object x, you can view its JSON string representation with a simple line of code:

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

Another variant of the dumps() function, called dump(), simply serializes the object to a text fileSo if f is a text file object opened for writing, we can do this:

json.dump(x, f)

To decode the object again, if f is a text file object which has been opened for reading:

x = json.load(f)

这种简单的序列化技术可以处理列表和字典,但序列化任意类实例为 JSON 需要一点额外的努力。The reference for the json module contains an explanation of this.

请参阅

pickle - the pickle module

Contrary to JSONpickle is a protocol which allows the serialization of arbitrarily complex Python objects. 因此,它只能用于 Python 而不能用来与其他语言编写的应用程序进行通信。默认情况下它也是不安全的:如果数据由熟练的攻击者精心设计, 反序列化来自一个不受信任源的 pickle 数据可以执行任意代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值