python输入输出

一、输出格式

推荐使用两种输出方式:​​expression statements​​​和​​print​​​语句。第三种输出方式是使用file对象中的​​write()​​方法。

通常需要对输出的格式进行更多控制,而不仅仅是将各值以空格分开。有两种途径可格式化输出。一种是手工处理。这种方式需要将整个字符串分片,然后用连接符连接各片;优点是可得到任何你能想到的格式。另一种方法是使用​​str.format()​​函数。

string模块包含了一个模板类,此类提供了将值转为字符串的方法——​​repr()和str()​​。

​str()​​​函数的作用是返回便于人读的字符串。​​repr()​​​函数的作用是返回可被解释器接受的字符串。对非特殊对象,​​str()和repr()​​将返回相同的值;如数字,列表,字典。而对于字符串,浮点数,二者返回结果不同。

例:

>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'

>>> repr(s)
"'Hello, world.'"

>>> str(1.0/7.0)
'0.142857142857'

>>> repr(1.0/7.0)
'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...

>>> hello = 'hello, world\n'
>>> hellos = repr(hello)
>>> print hellos
'hello, world\n'

>>> 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),
... print repr(x*x*x).rjust(4) # str.rjust(),右对齐字符串
...
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

​str.rjust()​​​表示右对齐字符串。相似的方法还有​​str.ljust()​​​,​​str.center()​​​;分别表示左对齐字符串,居中对齐字符串。使用这些方法时,若输入的字符串太长,这些方法不会截取部分字串输出,而是将之原封不动地输出。如果想输出部分字符,只需使用切片操作符。例:​​x.ljust(n)[:n]​​。

还有一个函数​​str.zfill(n)​​​,该函数会不断在字符串左侧填充​​0​​​,使得字符串长度达到​​n​​​。若字符串长度不小于​​n​​​,则不填充​​0​​。例:

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

​str.format()​​用法如下:

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

>>> print '{0} and {1}'.format('spam', 'eggs') # {}叫作格式域
spam and eggs
>>> print '{1} and {0}'.format('spam', 'eggs')
eggs and spam

上例不多解释。

格式域中的参数还可以是字串名。例:

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

字串名和数字可混合应用在格式域中。例:

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

​!s​​​代表​​str()​​​;​​!r​​​代表​​repr()​​。可以将它们应用在格式域中来格式化输出。例:

>>> import math
>>> print 'The value of PI is approximately {}.'.format(math.pi)
The value of PI is approximately 3.14159265359.
>>> print 'The value of PI is approximately {!r}.'.format(math.pi)
The value of PI is approximately 3.141592653589793.

还可以在格式域​​占位符(数字或字符串)​​​中使用​​:​​​和​​格式指定符​​。例:

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

# 规定 '.' 后有三位小数。

格式域​​:​​后跟一整数表示最小字符宽度。例:

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

格式域中可用​​[keyname]​​访问字典中的各值。例:

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

​**​​​只表示这是关键参数。这种写法在与内置函数,例​​vars()​​共用时很有用。

二、旧式字符串格式化

​%​​也可用来格式化字符串。例:

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

三、读写文件

​open()​​返回一个文件对象,其通常传入两个参数。例:

>>> f = open('workfile', 'w')
>>> print f
<open file 'workfile', mode 'w' at 80a0960>

第一个参数是个包含了文件名的字符串。第二个参数决定了文件的打开方式:​​r​​​表示以只读方式打开此文件,​​w​​​表示以只写方式打开(若有同名文件,将覆盖它);​​a​​​表示以追加的方式打开;​​r+​​​表示以​​读写方式​​​打开。第二个参数是可选的。若没有显式指定其值,默认值是​​r​​。即,以只读方式打开此文件。

windows平台下,打开模式值后加​​b​​​表示以二进制模式打开此文件。例:​​rb​​​,​​wb​​​,​​r+b​​。

需要注意的是:windows平台下对text文件和二进制文件之间划有区别。如果修改了二进制文件,例​​jpeg​​​或​​exe​​,会导致这些文件被损坏。而当读写text文本时windows系统又会自动修改文件结尾行的字符。

四、文件对象方法

假定一文件对象名为​​f​​。

读文件方法是​​f.read(size)​​​。此方法会读取一定量的数据并将其以字符串形式返回。​​size​​​是可选参数;若为空或负,则​​f.read(size)​​​将文件所有内容返回。如果读到文件尾,​​f.read()​​将返回空字符串。例:

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

​f.readline()​​​表示从文件中读取一行数据。每行结尾都有一个换行符。所以,如果​​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 line in f:
print line,

This is the first line of the file.
Second line of the file

若要读取所有行,使用函数​​f.readlines()​​即可。

写字符串到文件请使用​​f.write(string)​​。例:

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

如果还要写其它类型数据到文件,则需将这些类型数据转换成字符串后调用​​f.write()​​方法。例:

>>> value = ('the answer', 42)
>>> s = str(value)
>>> f.write(s)

​f.tell()​​​返回​​当前文件对象​​​在​​当前文件​​​中的位置。若要改变此对象的位置,请使用​​f.seek(offset,from_what)​​​。位置是由​​offset​​​值和​​参照点​​​位置值决定的。参照点位置值即,from_what,其值若为​​0​​​,表示以文件头为参考;为​​1​​​表示以当前位置为参考;为​​2​​​表示以文件尾为参考。此值默认为​​0​​。 例:

>>> f = open('workfile', 'r+')
>>> f.write('0123456789abcdef') #Ascii码,一个字符一字节。
>>> f.seek(5) # 移到第六字节处。因为默认位置指向第一字节,偏移5字节即指向第六字节。
>>> f.read(1)
'5'
>>> f.seek(-3, 2) # 以文件尾为参考点(默认指向f后一个位置),向字串反方向偏移3个字节。
>>> f.read(1)
'd'

​f.close()​​表示关闭文件并释放所有与之相关的资源。调用此方法后,再使用此文件对象就会出错。例:

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

用​​with​​​关键字处理文件操作,即使产生异常也能保证程序正常运行。相当于​​try-finally​​语块,而比之简洁。例:

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

五、用 json 保存结构化数据

从文件读写字符串很简单。但读取数字就有点复杂了。因为​​read()​​方法只能返回字符串。这就意味着还需要用一些类型转换的函数。而如果需要保存更加复杂的数据类型,如嵌套的列表或嵌套的字典,自行定义解析和序列化的方法就显得十分复杂。

为避免此种情形,python允许使用 json 类型的文件存放数据。模块为​​json​​。引入此模块后可将各种python数据类型转换为对应的字符串。这个过程叫做序列化。反之叫做反序列化。参与序列化与反序列化过程的字符串可能存在于某个文件中,这个文件可能存于本地,也可能存于远程某个机器中。

序列化函数为​​dumps()​​。简单用法如下:

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

与​​dumps()​​​函数有点不同的是​​dump()​​函数。此函数可将待序列化的对象序列化后写入文件。例:

json.dump(x, f) #f 是打开了的待写文件

解码(反序列化)这样做:

x = json.load(f) #f 是打开了的待读文件

这是简单的序列化技术。用于处理列表和字典这类复杂程度的结构还行,但是要序列化任意给定的类就显得捉襟见肘了。