7. 输入和输出¶
一个程åº�å�¯ä»¥æœ‰å‡ ç§�输出方å¼�:以人类å�¯è¯»çš„æ–¹å¼�打å�°æ•°æ�®ï¼Œæˆ–者写入一个文件供以å�Žä½¿ç”¨ã€‚æœ¬ç« å°†è®¨è®ºå‡ ç§�å�¯èƒ½æ€§ã€‚
7.1. æ ¼å¼�化输出¶
我们有两ç§�大相径åºåœ°è¾“出值方法:表达å¼�è¯å�¥ å’Œ print() 函数(第三ç§�访求是使用文件对象的 write() æ–¹æ³•ï¼Œæ ‡å‡†æ–‡ä»¶è¾“å‡ºå�¯ä»¥å�‚考 sys.stdout,详细内容å�‚è§�库å�‚考手册)。
é€šå¸¸ï¼Œä½ æƒ³è¦�对输出å�šæ›´å¤šçš„æ ¼å¼�控制,而ä¸�是简å�•的打å�°ä½¿ç”¨ç©ºæ ¼åˆ†éš”的值。有两ç§�方法å�¯ä»¥æ ¼å¼�åŒ–ä½ çš„è¾“å‡ºï¼šç¬¬ä¸€ç§�æ–¹æ³•æ˜¯ç”±ä½ è‡ªå·±å¤„ç�†æ•´ä¸ªå—符串,通过使用å—符串切割和连接æ“�作å�¯ä»¥åˆ›å»ºä»»ä½•ä½ æƒ³è¦�的输出形å¼�。string 类型包å�«ä¸€äº›å°†å—符串填充到指定列宽度的有用æ“�作,éš�å�Žå°±ä¼šè®¨è®ºè¿™äº›ã€‚第二ç§�方法是使用 str.format() 方法。
æ ‡å‡†æ¨¡å�— string 包括了一些æ“�作,将å—符串填充入给定列时,这些æ“�作很有用。éš�å�Žæˆ‘们会讨论这部分内容。第二ç§�方法是使用 Template 方法。
当然,还有一个问题,如何将值转化为å—符串?很幸è¿�,Python 有办法将任æ„�值转为å—ç¬¦ä¸²ï¼šå°†å®ƒä¼ å…¥ repr() 或 str() 函数。
函数 str() 用于将值转化为适于人阅读的形å¼�,而 repr() 转化为供解释器读å�–的形å¼�(如果没有ç‰ä»·çš„è¯æ³•,则会å�‘生 SyntaxError 异常)æŸ�对象没有适于人阅读的解释形å¼�çš„è¯�,str() 会返回与 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
(注æ„�第一个例å�,print() 在æ¯�åˆ—ä¹‹é—´åŠ äº†ä¸€ä¸ªç©ºæ ¼ï¼Œå®ƒæ€»æ˜¯åœ¨å�‚æ•°é—´åŠ å…¥ç©ºæ ¼ã€‚)
以上是一个 str.rjust() 方法的演示,它把å—符串输出到一列,并通过å�‘å·¦ä¾§å¡«å……ç©ºæ ¼æ�¥ä½¿å…¶å�³å¯¹é½�。类似的方法还有 str.ljust() å’Œ str.center()。这些函数å�ªæ˜¯è¾“出新的å—符串,并ä¸�改å�˜ä»€ä¹ˆã€‚如果输出的å—符串太长,它们也ä¸�会截æ–å®ƒï¼Œè€Œæ˜¯åŽŸæ ·è¾“å‡ºï¼Œè¿™ä¼šä½¿ä½ çš„è¾“å‡ºæ ¼å¼�å�˜å¾—混乱,ä¸�过总强过å�¦ä¸€ç§�选择(截æ–å—ç¬¦ä¸²ï¼‰ï¼Œå› ä¸ºé‚£æ ·ä¼šäº§ç”Ÿé”™è¯¯çš„è¾“å‡ºå€¼ï¼ˆå¦‚æžœä½ ç¡®å®žéœ€è¦�截æ–它,å�¯ä»¥ä½¿ç”¨åˆ‡å‰²æ“�作,例如:x.ljust(n)[:n] )。
还有å�¦ä¸€ä¸ªæ–¹æ³•, str.zfill() 它用于å�‘数值的å—符串表达左侧填充 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!"
大括å�·å’Œå…¶ä¸çš„å—符会被替æ�¢æˆ�ä¼ å…¥ str.format() çš„å�‚数。大括å�·ä¸çš„æ•°å€¼æŒ‡æ˜Žä½¿ç”¨ä¼ å…¥ str.format() 方法的对象ä¸çš„哪一个:
>>> print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
>>> print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam
如果在 str.format() 调用时使用关键å—å�‚数,å�¯ä»¥é€šè¿‡å�‚æ•°å��æ�¥å¼•用值:
>>> 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.
'!a' (应用 ascii()),'!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.
å—æ®µå��å�Žå…�许å�¯é€‰çš„ ':' å’Œæ ¼å¼�指令。这å…�è®¸å¯¹å€¼çš„æ ¼å¼�åŒ–åŠ ä»¥æ›´æ·±å…¥çš„æŽ§åˆ¶ã€‚ä¸‹ä¾‹å°† Pi 转为三ä½�精度。
>>> 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
å¦‚æžœä½ æœ‰ä¸ªå®žåœ¨æ˜¯å¾ˆé•¿çš„æ ¼å¼�化å—符串,ä¸�æƒ³åˆ†å‰²å®ƒã€‚å¦‚æžœä½ å�¯ä»¥ç”¨å‘½å��æ�¥å¼•ç”¨è¢«æ ¼å¼�化的å�˜é‡�而ä¸�是ä½�置就好了。有个简å�•的方法,å�¯ä»¥ä¼ 入一个å—å…¸ï¼Œç”¨ä¸æ‹¬å�·( '[]' )访问它的键:
>>> 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() 组å�ˆä½¿ç”¨é�žå¸¸æœ‰æ•ˆã€‚该函数返回包å�«æ‰€æœ‰å±€éƒ¨å�˜é‡�çš„å—典。
è¦�进一æ¥äº†è§£å—ç¬¦ä¸²æ ¼å¼�化方法 str.format(),å�‚è§� æ ¼å¼�å—ç¬¦ä¸²è¯æ³•。
7.1.1. æ—§å¼�çš„å—ç¬¦ä¸²æ ¼å¼�化¶
æ“�作符 % 也å�¯ä»¥ç”¨äºŽå—ç¬¦ä¸²æ ¼å¼�化。它以类似 sprintf()-style 的方å¼�è§£æž�å·¦å�‚数,将å�³å�‚数应用于æ¤ï¼Œå¾—åˆ°æ ¼å¼�化æ“�作生æˆ�çš„å—符串,例如:
>>> import math
>>> print('The value of PI is approximately %5.3f.' % math.pi)
The value of PI is approximately 3.142.
更多的信��以�� printf-style String Formatting 一节。
7.2. 文件读写¶
函数 open() 返回 文件对象,通常的用法需�两个�数:open(filename, mode)。
>>> f = open('workfile', 'w')
第一个å�‚数是一个å�«æœ‰æ–‡ä»¶å��çš„å—符串。第二个å�‚数也是一个å—符串,å�«æœ‰æ��è¿°å¦‚ä½•ä½¿ç”¨è¯¥æ–‡ä»¶çš„å‡ ä¸ªå—符。mode 为 'r' 时表示å�ªæ˜¯è¯»å�–文件;'w' 表示å�ªæ˜¯å†™å…¥æ–‡ä»¶ï¼ˆå·²ç»�å˜åœ¨çš„å�Œå��æ–‡ä»¶å°†è¢«åˆ æŽ‰ï¼‰ï¼›'a' è¡¨ç¤ºæ‰“å¼€æ–‡ä»¶è¿›è¡Œè¿½åŠ ï¼Œå†™å…¥åˆ°æ–‡ä»¶ä¸çš„任何数æ�®å°†è‡ªåŠ¨æ·»åŠ åˆ°æœ«å°¾ã€‚ 'r+' 表示打开文件进行读å�–和写入。mode å�‚数是å�¯é€‰çš„,默认为 'r'。
通常,文件以 文本 打开,这æ„�味ç�€ï¼Œä½ 从文件读出和å�‘文件写入的å—符串会被特定的编ç �æ–¹å¼�(默认是UTF-8)编ç �。模å¼�å�Žé�¢çš„ 'b' 以 二进制模å¼� 打开文件:数æ�®ä¼šä»¥å—节对象的形å¼�读出和写入。这ç§�模å¼�应该用于所有ä¸�包å�«æ–‡æœ¬çš„æ–‡ä»¶ã€‚
在文本模å¼�下,读å�–时默认会将平å�°æœ‰å…³çš„行结æ�Ÿç¬¦ï¼ˆUnix上是 \n , Windows上是 \r\n)转æ�¢ä¸º \n。在文本模å¼�下写入时,默认会将出现的 \n 转æ�¢æˆ�å¹³å�°æœ‰å…³çš„行结æ�Ÿç¬¦ã€‚è¿™ç§�暗地里的修改对 ASCII 文本文件没有问题,但会æ�Ÿå�� JPEG 或 EXE è¿™æ ·çš„äºŒè¿›åˆ¶æ–‡ä»¶ä¸çš„æ•°æ�®ã€‚使用二进制模å¼�读写æ¤ç±»æ–‡ä»¶æ—¶è¦�特别å°�心。
7.2.1. 文件对象方法¶
本节ä¸çš„示例都默认文件对象 f å·²ç»�创建。
è¦�读å�–文件内容,需è¦�调用 f.read(size),该方法读å�–若干数é‡�的数æ�®å¹¶ä»¥å—符串形å¼�返回其内容,size 是å�¯é€‰çš„æ•°å€¼ï¼ŒæŒ‡å®šå—符串长度。如果没有指定 size 或者指定为负数,就会读å�–并返回整个文件。当文件大å°�为当å‰�机器内å˜ä¸¤å€�时,就会产生问题。å��之,会尽å�¯èƒ½æŒ‰æ¯”较大的 size 读å�–和返回数æ�®ã€‚如果到了文件末尾,f.read() 会返回一个空å—符串(''):
>>> f.read()
'This is the entire file.\n'
>>> f.read()
''
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 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) 方法将 string 的内容写入文件,并返回写入å—符的长度:
>>> f.write('This is a test\n')
15
想è¦�写入其他é�žå—符串内容,首先è¦�将它转æ�¢ä¸ºå—符串:
>>> value = ('the answer', 42)
>>> s = str(value)
>>> f.write(s)
18
f.tell() 返回一个整数,代表文件对象在文件ä¸çš„æŒ‡é’ˆä½�置,该数值计é‡�了自文件开头到指针处的比特数。需è¦�改å�˜æ–‡ä»¶å¯¹è±¡æŒ‡é’ˆè¯�è¯�,使用 f.seek(offset,from_what)。指针在该æ“�作ä¸ä»ŽæŒ‡å®šçš„引用ä½�置移动 offset 比特,引用ä½�置由 from_what å�‚数指定。 from_what 值为 0 表示自文件起始处开始,1 表示自当å‰�文件指针ä½�置开始,2 表示自文件末尾开始。from_what å�¯ä»¥å¿½ç•¥ï¼Œå…¶é»˜è®¤å€¼ä¸ºé›¶ï¼Œæ¤æ—¶ä»Žæ–‡ä»¶å¤´å¼€å§‹:
>>> 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'
在文本文件ä¸ï¼ˆæ²¡æœ‰ä»¥ b 模å¼�打开),å�ªå…�许从文件头开始寻找(有个例外是用 seek(0, 2) 寻找文件的最末尾处)而且å�ˆæ³•çš„ å��ç§» 值å�ªèƒ½æ˜¯ f.tell() 返回的值或者是零。其它任何 å��ç§» 值都会产生未定义的行为。
å½“ä½ ä½¿ç”¨å®Œä¸€ä¸ªæ–‡ä»¶æ—¶ï¼Œè°ƒç”¨ f.close() 方法就å�¯ä»¥å…³é—它并释放其å� 用的所有系统资æº�。 在调用 f.close() 方法å�Žï¼Œè¯•图å†�次使用文件对象将会自动失败。
>>> f.close()
>>> f.read()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: I/O operation on closed file
ç”¨å…³é”®å— with 处ç�†æ–‡ä»¶å¯¹è±¡æ˜¯ä¸ªå¥½ä¹ 惯。它的先进之处在于文件用完å�Žä¼šè‡ªåЍ关é—,就算å�‘生异常也没关系。它是 try-finally å�—的简写:
>>> with open('workfile', 'r') as f:
... read_data = f.read()
>>> f.closed
True
文件对象还有一些ä¸�å¤ªå¸¸ç”¨çš„é™„åŠ æ–¹æ³•ï¼Œæ¯”å¦‚ isatty() å’Œ truncate() 在库å�‚è€ƒæ‰‹å†Œä¸æœ‰æ–‡ä»¶å¯¹è±¡çš„完整指å�—。
7.2.2. 使用 json å˜å‚¨ç»“构化数æ�®Â¶
从文件ä¸è¯»å†™å—符串很容易。数值就è¦�å¤šè´¹ç‚¹å„¿å‘¨æŠ˜ï¼Œå› ä¸º read() 方法å�ªä¼šè¿”回å—ç¬¦ä¸²ï¼Œåº”å°†å…¶ä¼ å…¥ int() è¿™æ ·çš„å‡½æ•°ï¼Œå°±å�¯ä»¥å°† '123' è¿™æ ·çš„å—符串转æ�¢ä¸ºå¯¹åº”的数值 123ã€‚å½“ä½ æƒ³è¦�ä¿�å˜æ›´ä¸ºå¤�æ�‚的数æ�®ç±»åž‹ï¼Œä¾‹å¦‚嵌套的列表和å—典,手工解æž�å’Œåº�列化它们将å�˜å¾—æ›´å¤�æ�‚。
好在用户ä¸�是é�žå¾—自己编写和调试ä¿�å˜å¤�æ�‚æ•°æ�®ç±»åž‹çš„代ç �,Python å…�è®¸ä½ ä½¿ç”¨å¸¸ç”¨çš„æ•°æ�®äº¤æ�¢æ ¼å¼� JSON(JavaScript Object Notationï¼‰ã€‚æ ‡å‡†æ¨¡å�— json å�¯ä»¥æŽ¥å�— Python æ•°æ�®ç»“构,并将它们转æ�¢ä¸ºå—符串表示形å¼�ï¼›æ¤è¿‡ç¨‹ç§°ä¸º åº�列化。从å—符串表示形å¼�é‡�新构建数æ�®ç»“构称为 å��åº�列化。åº�列化和å��åº�列化的过程ä¸ï¼Œè¡¨ç¤ºè¯¥å¯¹è±¡çš„å—符串å�¯ä»¥å˜å‚¨åœ¨æ–‡ä»¶æˆ–æ•°æ�®ä¸ï¼Œä¹Ÿå�¯ä»¥é€šè¿‡ç½‘ç»œè¿žæŽ¥ä¼ é€�给远程的机器。
Note
JSON æ ¼å¼�ç»�常用于现代应用程åº�ä¸è¿›è¡Œæ•°æ�®äº¤æ�¢ã€‚许多程åº�员都已ç»�熟悉它了,使它æˆ�为相互å��作的一个ä¸�错的选择。
å¦‚æžœä½ æœ‰ä¸€ä¸ªå¯¹è±¡ xï¼Œä½ å�¯ä»¥ç”¨ç®€å�•的一行代ç �查看其 JSON å—符串表示形å¼�:
>>> json.dumps([1, 'simple', 'list'])
'[1, "simple", "list"]'
dumps() 函数的å�¦å¤–一个å�˜ä½“ dump(),直接将对象åº�列化到一个文件。所以如果 f 是为写入而打开的一个 文件对象,我们å�¯ä»¥è¿™æ ·å�š:
json.dump(x, f)
为了é‡�æ–°è§£ç �对象,如果 f 是为读å�–而打开的 文件对象:
x = json.load(f)
è¿™ç§�简å�•çš„åº�列化技术å�¯ä»¥å¤„ç�†åˆ—表和å—典,但åº�列化任æ„�类实例为 JSON 需è¦�一点é¢�外的努力。 json 模å�—çš„æ‰‹å†Œå¯¹æ¤æœ‰è¯¦ç»†çš„解释。
See also
pickle - pickle 模�
与 JSON ä¸�å�Œï¼Œpickle 是一个å��议,它å…�许任æ„�å¤�æ�‚çš„ Python 对象的åº�åˆ—åŒ–ã€‚å› æ¤ï¼Œå®ƒå�ªèƒ½ç”¨äºŽ Python 而ä¸�能用æ�¥ä¸Žå…¶ä»–è¯è¨€ç¼–写的应用程åº�进行通信。默认情况下它也是ä¸�安全的:如果数æ�®ç”±ç†Ÿç»ƒçš„æ”»å‡»è€…精心设计, å��åº�列化æ�¥è‡ªä¸€ä¸ªä¸�å�—ä¿¡ä»»æº�çš„ pickle æ•°æ�®å�¯ä»¥æ‰§è¡Œä»»æ„�代ç �。