python輸入和輸出

輸入和輸出

一個程序可以有幾種輸出方式:以人類可讀的方式列印數據,或者寫入一個文件供以後使用。 本章將討論幾種可能性。

格式化輸出

我們有兩種大相徑庭的輸出值方法: 表達式語句 和 print 語句。(第三種方法是使用文件對象的write() 方法,標準文件輸出可以參考 sys.stdout 。詳細內容參見庫參考手冊。)

通常,你想要對輸出做更多的格式控制,而不是簡單的列印使用空格分隔的值。 有兩種方法可以格式化你的輸出: 第一種方法是由你自己處理整個字元串,通過使用字元串切割和連接操作可以創建任何你想要的輸出形式。string 類型包含一些將字元串填充到指定列寬度的有用操作,隨後就會討論這些。 第二種方法是使用 str.format() 方法。

Advertisements

標準模塊 string 包括了一些操作,將字元串填充入給定列時,這些操作很有用。隨後我們會討論這部分內容。第二種方法是使用 Template 方法。

當然,還有一個問題,如何將值轉化為字元串?很幸運,Python 有辦法將任意值轉為字元串:將它傳入 repr() 或 str() 函數。

函數 str() 用於將值轉化為適於人閱讀的形式,而 repr() 轉化為供解釋器讀取的形式(如果沒有等價的語法,則會發生 SyntaxError 異常) 某對象沒有適於人閱讀的解釋形式的話, str() 會返回與 repr() 等同的值。很多類型,諸如數值或鏈表、字典這樣的結構,針對各函數都有著統一的解讀方式。字元串和浮點數,有著獨特的解讀方式。

Advertisements

下面有些例子:

>>> 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 sThe 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)... # 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 72910 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 72910 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.

'!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 ==> 4098Dcab ==> 7678Sjoerd ==> 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() ,參見 formatstrings 。

7.1.1. 舊式的字元串格式化

操作符 % 也可以用於字元串格式化。它以類似 sprintf()-style 的方式解析左參數,將右參數應用於此,得到格式化操作生成的字元串,例如:

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

進一步的信息可以參見 string-formatting 一節。 qq:1900526093

文件讀寫

函數 open() 返迴文件對象,通常的用法需要兩個參數: open(filename, mode)。

>>> 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 平台上文本文件與二進位文件是有區別的,讀寫文本文件時,行尾會自動添加行結束符。這種後台操作方式對 ASCII 文本文件沒有什麼問題,但是操作 JPEG 或 EXE這樣的二進位文件時就會產生破壞。在操作這些文件時一定要記得以二進位模式打開。在 Unix 上,加一個 'b' 模式也一樣是無害的,所以你可以一切二進位文件處理中平台無關的使用它。

文件對象方法

本節中的示例都默認文件對象 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()''

f.readlines() 返回一個列表,其中包含了文件中所有的數據行。如果給定了 sizehint 參數,就會讀入多於一行的比特數,從中返回多行文本。這個功能通常用於高效讀取大型行文件,避免了將整個文件讀入內存。這種操作只返回完整的行。

>>> f.readlines()['This is the first line of the file.\n', 'Second line of the file\n']

一種替代的方法是通過遍歷文件對象來讀取文件行。 這是一種內存高效、快速,並且代碼簡潔的方式:

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

雖然這種替代方法更簡單,但並不具備細節控制能力。 因為這兩種方法處理行緩存的方式不同,千萬不能搞混。

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('/tmp/workfile', 'rb+')>>> f.write(b'0123456789abcdef')16>>> f.seek(5) # Go to the 6th byte in the file5>>> f.read(1)b'5'>>> f.seek(-3, 2) # Go to the 3rd byte before the end13>>> f.read(1)b'd'

在文本文件中(那些沒有使用 b 模式選項打開的文件),只允許從文件頭開始計算相對位置(使用 seek(0, 2) 從文件尾計算時就會引發異常)。

當你使用完一個文件時,調用 f.close() 方法就可以關閉它並釋放其佔用的所有系統資源。 在調用f.close() 方法后,試圖再次使用文件對象將會自動失敗:

>>> f.close()>>> f.read()Traceback (most recent call last):

File "<stdin>", line 1, in ?ValueError: I/O operation on closed fileTraceback (most recent call last):

File "<stdin>", line 1, in ?ValueError: I/O operation on closed file

用關鍵字 with 處理文件對象是個好習慣。它的先進之處在於文件用完後會自動關閉,就算髮生異常也沒關係。它是 try-finally 塊的簡寫:

>>> with open('/tmp/workfile', 'r') as f:... read_data = f.read()>>> f.closedTrue

文件對象還有一些不太常用的附加方法,比如 isatty() 和 truncate() 在庫參考手冊中有文件對象的完整指南。

pickle 模塊

我們可以很容易的讀寫文件中的字元串。數值就要多費點兒周折,因為 read() 方法只會返回字元串,應該將其傳入 int() 這樣的方法中,就可以將 '123' 這樣的字元轉為對應的數值 123。不過,當你需要保存更為複雜的數據類型,例如列表、字典,類的實例,事情就會變得更複雜了。

好在用戶不必要非得自己編寫和調試保存複雜數據類型的代碼。 Python 提供了一個名為 pickle 的標準模塊。這是一個令人讚歎的模塊,幾乎可以把任何 Python 對象 (甚至是一些 Python 代碼段!)表達為為字元串,這一過程稱之為封裝 ( pickling )。從字元串表達出重新構造對象稱之為拆封( unpickling )。封裝狀態中的對象可以存儲在文件或對象中,也可以通過網路在遠程的機器之間傳輸。

如果你有一個對象 x ,一個以寫模式打開的文件對象 f ,封裝對象的最簡單的方法只需要一行代碼:

pickle.dump(x, f)

如果 f 是一個以讀模式打開的文件對象,就可以重裝拆封這個對象:

x = pickle.load(f)

(如果不想把封裝的數據寫入文件,這裡還有一些其它的變化可用。完整的 pickle 文檔請見Python 庫參考手冊)。

pickle 是存儲 Python 對象以供其它程序或其本身以後調用的標準方法。提供這一組技術的是一個 持久化 對象( persistent object )。因為 pickle 的用途很廣泛,很多 Python 擴展的作者都非常注意類似矩陣這樣的新數據類型是否適合封裝和拆封。

以上是小編的總結,希望下次帶來更多的知識點,

謝謝支持,如果需要更多文章或視頻資料的童鞋,可以加群:516126034。大家一起學習,交流。

Advertisements

你可能會喜歡