新聞中心
7. 輸入與輸出
程序輸出有幾種顯示方式;數(shù)據(jù)既可以輸出供人閱讀的形式,也可以寫入文件備用。本章探討一些可用的方式。

為安康等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及安康網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為做網(wǎng)站、成都網(wǎng)站制作、安康網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
7.1. 更復(fù)雜的輸出格式
至此,我們已學(xué)習(xí)了兩種寫入值的方法:表達(dá)式語(yǔ)句 和 print() 函數(shù)。第三種方法是使用文件對(duì)象的 write() 方法;標(biāo)準(zhǔn)輸出文件稱為 sys.stdout。詳見(jiàn)標(biāo)準(zhǔn)庫(kù)參考。
對(duì)輸出格式的控制不只是打印空格分隔的值,還需要更多方式。格式化輸出包括以下幾種方法。
-
使用 格式化字符串字面值 ,要在字符串開(kāi)頭的引號(hào)/三引號(hào)前添加
f或F。在這種字符串中,可以在{和}字符之間輸入引用的變量,或字面值的 python 表達(dá)式。>>> year = 2016>>> event = 'Referendum'>>> f'Results of the {year} {event}''Results of the 2016 Referendum'
-
字符串的 str.format() 方法需要更多手動(dòng)操作。該方法也用
{和}標(biāo)記替換變量的位置,雖然這種方法支持詳細(xì)的格式化指令,但需要提供格式化信息。>>> yes_votes = 42_572_654>>> no_votes = 43_132_495>>> percentage = yes_votes / (yes_votes + no_votes)>>> '{:-9} YES votes {:2.2%}'.format(yes_votes, percentage)' 42572654 YES votes 49.67%'
-
最后,還可以用字符串切片和合并操作完成字符串處理操作,創(chuàng)建任何排版布局。字符串類型還支持將字符串按給定列寬進(jìn)行填充,這些方法也很有用。
如果不需要花哨的輸出,只想快速顯示變量進(jìn)行調(diào)試,可以用 repr() 或 str() 函數(shù)把值轉(zhuǎn)化為字符串。
str() 函數(shù)返回供人閱讀的值,repr() 則生成適于解釋器讀取的值(如果沒(méi)有等效的語(yǔ)法,則強(qiáng)制執(zhí)行 SyntaxError)。對(duì)于沒(méi)有支持供人閱讀展示結(jié)果的對(duì)象, str() 返回與 repr() 相同的值。一般情況下,數(shù)字、列表或字典等結(jié)構(gòu)的值,使用這兩個(gè)函數(shù)輸出的表現(xiàn)形式是一樣的。字符串有兩種不同的表現(xiàn)形式。
示例如下:
>>> 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'))"
string 模塊包含 Template 類,提供了將值替換為字符串的另一種方法。該類使用 $x 占位符,并用字典的值進(jìn)行替換,但對(duì)格式控制的支持比較有限。
7.1.1. 格式化字符串字面值
格式化字符串字面值 (簡(jiǎn)稱為 f-字符串)在字符串前加前綴 f 或 F,通過(guò) {expression} 表達(dá)式,把 Python 表達(dá)式的值添加到字符串內(nèi)。
格式說(shuō)明符是可選的,寫在表達(dá)式后面,可以更好地控制格式化值的方式。下例將 pi 舍入到小數(shù)點(diǎn)后三位:
>>> import math>>> print(f'The value of pi is approximately {math.pi:.3f}.')The value of pi is approximately 3.142.
在 ':' 后傳遞整數(shù),為該字段設(shè)置最小字符寬度,常用于列對(duì)齊:
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}>>> for name, phone in table.items():... print(f'{name:10} ==> {phone:10d}')...Sjoerd ==> 4127Jack ==> 4098Dcab ==> 7678
還有一些修飾符可以在格式化前轉(zhuǎn)換值。 '!a' 應(yīng)用 ascii() ,'!s' 應(yīng)用 str(),'!r' 應(yīng)用 repr():
>>> animals = 'eels'>>> print(f'My hovercraft is full of {animals}.')My hovercraft is full of eels.>>> print(f'My hovercraft is full of {animals!r}.')My hovercraft is full of 'eels'.
The = specifier can be used to expand an expression to the text of the expression, an equal sign, then the representation of the evaluated expression:
>>> bugs = 'roaches'>>> count = 13>>> area = 'living room'>>> print(f'Debugging {bugs=} {count=} {area=}')Debugging bugs='roaches' count=13 area='living room'
See self-documenting expressions for more information on the = specifier. For a reference on these format specifications, see the reference guide for the 格式規(guī)格迷你語(yǔ)言.
7.1.2. 字符串 format() 方法
str.format() 方法的基本用法如下所示:
>>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))We are the knights who say "Ni!"
花括號(hào)及之內(nèi)的字符(稱為格式字段)被替換為傳遞給 str.format() 方法的對(duì)象?;ɡㄌ?hào)中的數(shù)字表示傳遞給 str.format() 方法的對(duì)象所在的位置。
>>> print('{0} and {1}'.format('spam', 'eggs'))spam and eggs>>> print('{1} and {0}'.format('spam', 'eggs'))eggs and spam
str.format() 方法中使用關(guān)鍵字參數(shù)名引用值。
>>> print('This {food} is {adjective}.'.format(... food='spam', adjective='absolutely horrible'))This spam is absolutely horrible.
位置參數(shù)和關(guān)鍵字參數(shù)可以任意組合:
>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',... other='Georg'))The story of Bill, Manfred, and Georg.
如果不想分拆較長(zhǎng)的格式字符串,最好按名稱引用變量進(jìn)行格式化,不要按位置。這項(xiàng)操作可以通過(guò)傳遞字典,并用方括號(hào) '[]' 訪問(wèn)鍵來(lái)完成。
>>> 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
This could also be done by passing the table dictionary as keyword arguments with the ** notation.
>>> 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
與內(nèi)置函數(shù) vars() 結(jié)合使用時(shí),這種方式非常實(shí)用,可以返回包含所有局部變量的字典。
As an example, the following lines produce a tidily aligned set of columns giving integers and their squares and cubes:
>>> for x in range(1, 11):... print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))...1 1 12 4 83 9 274 16 645 25 1256 36 2167 49 3438 64 5129 81 72910 100 1000
str.format() 進(jìn)行字符串格式化的完整概述詳見(jiàn) 格式字符串語(yǔ)法 。
7.1.3. 手動(dòng)格式化字符串
下面是使用手動(dòng)格式化方式實(shí)現(xiàn)的同一個(gè)平方和立方的表:
>>> 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 12 4 83 9 274 16 645 25 1256 36 2167 49 3438 64 5129 81 72910 100 1000
(注意,每列之間的空格是通過(guò)使用 print() 添加的:它總在其參數(shù)間添加空格。)
字符串對(duì)象的 str.rjust() 方法通過(guò)在左側(cè)填充空格,對(duì)給定寬度字段中的字符串進(jìn)行右對(duì)齊。同類方法還有 str.ljust() 和 str.center() 。這些方法不寫入任何內(nèi)容,只返回一個(gè)新字符串,如果輸入的字符串太長(zhǎng),它們不會(huì)截?cái)嘧址?,而是原樣返回;雖然這種方式會(huì)弄亂列布局,但也比另一種方法好,后者在顯示值時(shí)可能不準(zhǔn)確(如果真的想截?cái)嘧址梢允褂?x.ljust(n)[:n] 這樣的切片操作 。)
另一種方法是 str.zfill() ,該方法在數(shù)字字符串左邊填充零,且能識(shí)別正負(fù)號(hào):
>>> '12'.zfill(5)'00012'>>> '-3.14'.zfill(7)'-003.14'>>> '3.14159265359'.zfill(5)'3.14159265359'
7.1.4. 舊式字符串格式化方法
% 運(yùn)算符(求余符)也可用于字符串格式化。給定 'string' % values,則 string 中的 % 實(shí)例會(huì)以零個(gè)或多個(gè) values 元素替換。此操作被稱為字符串插值。例如:
>>> import math>>> print('The value of pi is approximately %5.3f.' % math.pi)The value of pi is approximately 3.142.
printf 風(fēng)格的字符串格式化 小節(jié)介紹更多相關(guān)內(nèi)容。
7.2. 讀寫文件
open() 返回一個(gè) file object ,最常使用的是兩個(gè)位置參數(shù)和一個(gè)關(guān)鍵字參數(shù):open(filename, mode, encoding=None)
>>> f = open('workfile', 'w', encoding="utf-8")
第一個(gè)實(shí)參是文件名字符串。第二個(gè)實(shí)參是包含描述文件使用方式字符的字符串。mode 的值包括 'r' ,表示文件只能讀?。?code>'w' 表示只能寫入(現(xiàn)有同名文件會(huì)被覆蓋);'a' 表示打開(kāi)文件并追加內(nèi)容,任何寫入的數(shù)據(jù)會(huì)自動(dòng)添加到文件末尾。'r+' 表示打開(kāi)文件進(jìn)行讀寫。mode 實(shí)參是可選的,省略時(shí)的默認(rèn)值為 'r'。
通常情況下,文件是以 text mode 打開(kāi)的,也就是說(shuō),你從文件中讀寫字符串,這些字符串是以特定的 encoding 編碼的。如果沒(méi)有指定 encoding ,默認(rèn)的是與平臺(tái)有關(guān)的(見(jiàn) open() )。因?yàn)?UTF-8 是現(xiàn)代事實(shí)上的標(biāo)準(zhǔn),除非你知道你需要使用一個(gè)不同的編碼,否則建議使用 encoding="utf-8" 。在模式后面加上一個(gè) 'b' ,可以用 binary mode 打開(kāi)文件。二進(jìn)制模式的數(shù)據(jù)是以 bytes 對(duì)象的形式讀寫的。在二進(jìn)制模式下打開(kāi)文件時(shí),你不能指定 encoding 。
在文本模式下讀取文件時(shí),默認(rèn)把平臺(tái)特定的行結(jié)束符(Unix 上為 \n, Windows 上為 \r\n)轉(zhuǎn)換為 \n。在文本模式下寫入數(shù)據(jù)時(shí),默認(rèn)把 \n 轉(zhuǎn)換回平臺(tái)特定結(jié)束符。這種操作方式在后臺(tái)修改文件數(shù)據(jù)對(duì)文本文件來(lái)說(shuō)沒(méi)有問(wèn)題,但會(huì)破壞 JPEG 或 EXE 等二進(jìn)制文件中的數(shù)據(jù)。注意,在讀寫此類文件時(shí),一定要使用二進(jìn)制模式。
在處理文件對(duì)象時(shí),最好使用 with 關(guān)鍵字。優(yōu)點(diǎn)是,子句體結(jié)束后,文件會(huì)正確關(guān)閉,即便觸發(fā)異常也可以。而且,使用 with 相比等效的 try-finally 代碼塊要簡(jiǎn)短得多:
>>> with open('workfile', encoding="utf-8") as f:... read_data = f.read()>>> # We can check that the file has been automatically closed.>>> f.closedTrue
如果沒(méi)有使用 with 關(guān)鍵字,則應(yīng)調(diào)用 f.close() 關(guān)閉文件,即可釋放文件占用的系統(tǒng)資源。
警告
調(diào)用 f.write() 時(shí),未使用 with 關(guān)鍵字,或未調(diào)用 f.close(),即使程序正常退出,也**可能** 導(dǎo)致 f.write() 的參數(shù)沒(méi)有完全寫入磁盤。
通過(guò) with 語(yǔ)句,或調(diào)用 f.close() 關(guān)閉文件對(duì)象后,再次使用該文件對(duì)象將會(huì)失敗。
>>> f.close()>>> f.read()Traceback (most recent call last):File "", line 1, in ValueError: I/O operation on closed file.
7.2.1. 文件對(duì)象的方法
本節(jié)下文中的例子假定已創(chuàng)建 f 文件對(duì)象。
f.read(size) 可用于讀取文件內(nèi)容,它會(huì)讀取一些數(shù)據(jù),并返回字符串(文本模式),或字節(jié)串對(duì)象(在二進(jìn)制模式下)。 size 是可選的數(shù)值參數(shù)。省略 size 或 size 為負(fù)數(shù)時(shí),讀取并返回整個(gè)文件的內(nèi)容;文件大小是內(nèi)存的兩倍時(shí),會(huì)出現(xiàn)問(wèn)題。size 取其他值時(shí),讀取并返回最多 size 個(gè)字符(文本模式)或 size 個(gè)字節(jié)(二進(jìn)制模式)。如已到達(dá)文件末尾,f.read() 返回空字符串('')。
>>> f.read()'This is the entire file.\n'>>> f.read()''
f.readline() 從文件中讀取單行數(shù)據(jù);字符串末尾保留換行符(\n),只有在文件不以換行符結(jié)尾時(shí),文件的最后一行才會(huì)省略換行符。這種方式讓返回值清晰明確;只要 f.readline() 返回空字符串,就表示已經(jīng)到達(dá)了文件末尾,空行使用 '\n' 表示,該字符串只包含一個(gè)換行符。
>>> f.readline()'This is the first line of the file.\n'>>> f.readline()'Second line of the file\n'>>> f.readline()''
從文件中讀取多行時(shí),可以用循環(huán)遍歷整個(gè)文件對(duì)象。這種操作能高效利用內(nèi)存,快速,且代碼簡(jiǎn)單:
>>> 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 的內(nèi)容寫入文件,并返回寫入的字符數(shù)。
>>> f.write('This is a test\n')15
寫入其他類型的對(duì)象前,要先把它們轉(zhuǎn)化為字符串(文本模式)或字節(jié)對(duì)象(二進(jìn)制模式):
>>> value = ('the answer', 42)>>> s = str(value) # convert the tuple to string>>> f.write(s)18
f.tell() 返回整數(shù),給出文件對(duì)象在文件中的當(dāng)前位置,表示為二進(jìn)制模式下時(shí)從文件開(kāi)始的字節(jié)數(shù),以及文本模式下的意義不明的數(shù)字。
f.seek(offset, whence) 可以改變文件對(duì)象的位置。通過(guò)向參考點(diǎn)添加 offset 計(jì)算位置;參考點(diǎn)由 whence 參數(shù)指定。 whence 值為 0 時(shí),表示從文件開(kāi)頭計(jì)算,1 表示使用當(dāng)前文件位置,2 表示使用文件末尾作為參考點(diǎn)。省略 whence 時(shí),其默認(rèn)值為 0,即使用文件開(kāi)頭作為參考點(diǎn)。
>>> f = open('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 時(shí)打開(kāi)的文件)中,只允許相對(duì)于文件開(kāi)頭搜索(使用 seek(0, 2) 搜索到文件末尾是個(gè)例外),唯一有效的 offset 值是能從 f.tell() 中返回的,或 0。其他 offset 值都會(huì)產(chǎn)生未定義的行為。
文件對(duì)象還支持 isatty() 和 truncate() 等方法,但不常用;文件對(duì)象的完整指南詳見(jiàn)庫(kù)參考。
7.2.2. 使用 json 保存結(jié)構(gòu)化數(shù)據(jù)
從文件寫入或讀取字符串很簡(jiǎn)單,數(shù)字則稍顯麻煩,因?yàn)?read() 方法只返回字符串,這些字符串必須傳遞給 int() 這樣的函數(shù),接受 '123' 這樣的字符串,并返回?cái)?shù)字值 123。保存嵌套列表、字典等復(fù)雜數(shù)據(jù)類型時(shí),手動(dòng)解析和序列化的操作非常復(fù)雜。
Rather than having users constantly writing and debugging code to save complicated data types to files, Python allows you to use the popular data interchange format called JSON (JavaScript Object Notation). The standard module called json can take Python data hierarchies, and convert them to string representations; this process is called serializing. Reconstructing the data from the string representation is called deserializing. Between serializing and deserializing, the string representing the object may have been stored in a file or data, or sent over a network connection to some distant machine.
備注
JSON 格式通常用于現(xiàn)代應(yīng)用程序的數(shù)據(jù)交換。程序員早已對(duì)它耳熟能詳,可謂是交互操作的不二之選。
只需一行簡(jiǎn)單的代碼即可查看某個(gè)對(duì)象的 JSON 字符串表現(xiàn)形式:
>>> import json>>> x = [1, 'simple', 'list']>>> json.dumps(x)'[1, "simple", "list"]'
dumps() 函數(shù)還有一個(gè)變體, dump() ,它只將對(duì)象序列化為 text file 。因此,如果 f 是 text file 對(duì)象,可以這樣做:
json.dump(x, f)
要再次解碼對(duì)象,如果 f 是已打開(kāi)、供讀取的 binary file 或 text file 對(duì)象:
x = json.load(f)
備注
JSON文件必須以UTF-8編碼。當(dāng)打開(kāi)JSON文件作為一個(gè) text file 用于讀寫時(shí),使用 encoding="utf-8" 。
這種簡(jiǎn)單的序列化技術(shù)可以處理列表和字典,但在 JSON 中序列化任意類的實(shí)例,則需要付出額外努力。json 模塊的參考包含對(duì)此的解釋。
參見(jiàn)
pickle - 封存模塊
與 JSON 不同,pickle 是一種允許對(duì)復(fù)雜 Python 對(duì)象進(jìn)行序列化的協(xié)議。因此,它為 Python 所特有,不能用于與其他語(yǔ)言編寫的應(yīng)用程序通信。默認(rèn)情況下它也是不安全的:如果解序化的數(shù)據(jù)是由手段高明的攻擊者精心設(shè)計(jì)的,這種不受信任來(lái)源的 pickle 數(shù)據(jù)可以執(zhí)行任意代碼。
網(wǎng)頁(yè)名稱:創(chuàng)新互聯(lián)Python教程:7.輸入與輸出
標(biāo)題網(wǎng)址:http://m.fisionsoft.com.cn/article/dppsiec.html


咨詢
建站咨詢
