Python教程:7. 輸入和輸出
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 資料可以執行任意程式碼
。
相關文章
- Python 輸入和輸出Python
- Python輸入和輸出(IO)Python
- python基礎篇-輸入和輸出Python
- Python的輸入輸出Python
- 基本的python知識 (輸入和輸出)Python
- python ----輸入輸出 變數Python變數
- python 標準輸入輸出Python
- ACM的Python版輸入輸出ACMPython
- 初學Python(六)——輸入輸出Python
- 格式化輸入和輸出
- 輸入輸出
- Python 快速教程(進階篇02):文字檔案的輸入輸出Python
- python:檔案的輸入與輸出Python
- Python資料的輸入與輸出Python
- 輸入和輸出基礎語法
- JAVA筆記(12)——輸入和輸出Java筆記
- Python教程:input接受輸入Python
- 輸入輸出流
- 關於Linux bash shell 輸入、輸出和錯誤輸出Linux
- python基本語法_輸入輸出詳解Python
- 物聯網學習教程——格式輸入與輸出
- 【C++】輸入輸出C++
- Java 輸入輸出流Java
- 輸入輸出系統
- JAVA輸入輸出流Java
- 新手學python之Python的輸入輸出函式Python函式
- Java中資料輸入輸出流——DataInputStream和DataOutputStreamJavaAI
- linux中的輸入與輸出管理(重定向輸入,輸出,管道符)Linux
- C++中的檔案輸入/輸出(3):掌握輸入/輸出流 (轉)C++
- 資料的輸入輸出
- Java —— 標準輸入輸出Java
- 排序,檔案輸入輸出排序
- 03 資料輸入-輸出
- 檔案操作-輸入輸出
- C語言輸入輸出C語言
- Java基礎輸入輸出Java
- 常用輸入輸出函式函式
- C語言之輸入輸出C語言