python3測試工具開發快速入門教程7輸入和輸出
python有多種輸出方式:螢幕列印資料,或者寫入檔案。
格式化輸出
我們有兩種大相徑庭地輸出值方法:表示式語句* 和print() 函式(第三種方法使用檔案物件的write()方法,標準檔案輸出可以參考sys.stdout)。
通常需要對輸出做更多的格式控制,而不是簡單的列印空格分隔值。有兩種方法可以格式化你的輸出:第一種方法是由你自己處理整個字串,通過使用字串切片和連線操作可以建立任何你想要的輸出形式。string 型別包含一些將字串填充到指定列寬度的有用操作。第二種方法是使用str.format() 方法。
標準模組string 的Template 類可以替換字串的值。(python標準模組介紹-string:文字常量和模板 )
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)) ... 111 248 3927 41664 525125 636216 749343 864512 981729 10 100 1000 >>> for x in range(1, 11): ...print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x)) ... 111 248 3927 41664 525125 636216 749343 864512 981729 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()
)可在格式化之前轉換值:
>>> contents = 'eels' >>> print('My hovercraft is full of {}.'.format(contents)) My hovercraft is full of eels. >>> print('My hovercraft is full of {!r}.'.format(contents)) My hovercraft is full of 'eels'.
欄位名後允許可選的':'
和格式指令。這允許對值的格式化更多的控制。下例將 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() ,參見格式字串語法 。
- 舊式的字串格式化
操作符%
也可以用於字串格式化。它以類似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 。
檔案讀寫
函式open()
返回檔案物件
,通常的用法需要兩個引數:open(filename, mode)
。
>>> f = open('workfile', 'w')
第一個引數是檔名。第二個引數也是字串,含有描述如何使用該檔案的幾個字元。mode為'r' 時表示只是讀取檔案;'w'
表示只是寫入檔案(已經存在的同名檔案將被刪掉); 'a'表示開啟檔案進行追加,寫入到檔案中的任何資料將自動新增到末尾。 'r+' 表示開啟檔案進行讀取和寫入。mode引數是可選的,預設為'r' 。
通常,檔案以text模式開啟,這意味著,你從檔案讀出和向檔案寫入的字串會被特定的編碼方式(類Linux預設是UTF-8,windows經常為gbk,容易導致一些IO問題)編碼。模式後面的'b'以二進位制模式開啟檔案:資料會以位元組物件的形式讀出和寫入。這種模式應該用於所有不包含文字的檔案。
在文字模式下,讀取時預設會將平臺有關的行結束符(Unix上是\n
, Windows上是\r\n
)轉換為\n
。在文字模式下寫入時,預設會將出現的\n
轉換成平臺有關的行結束符。這種暗地裡的修改對 ASCII 文字檔案沒有問題,但會損壞JPEG
或EXE
這樣的二進位制檔案中的資料。使用二進位制模式讀寫此類檔案時要特別小心。
用關鍵字with
處理檔案物件是個好習慣。它的好處在於檔案用完後會自動關閉,就算髮生異常也沒關係,且比
try
-
finally
更簡潔:
>>> with open('workfile') as f: ...read_data = f.read() >>> f.closed True
不用with關鍵字則應該呼叫 f.close() 來關閉檔案,並立即釋放它使用的系統資源。 如果沒有明確地關閉檔案,Python的垃圾回收器最終會銷燬這個物件併為你關閉這個開啟的檔案,但是這個檔案可能會保持開啟一段時間。 另一個風險是不同的Python實現會在不同的時間進行這種清理。
在關閉檔案物件之後,可以通過with語句或通過呼叫f.close()來嘗試使用檔案物件將自動失敗。
>>> f.close() >>> f.read() Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: I/O operation on closed file
檔案物件方法
本節中的示例都預設檔案物件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)# convert the tuple to string >>> f.write(s) 18
f.tell() 返回一個整數,代表檔案物件在檔案中的指標位置,該數值計量了自檔案開頭到指標處的位元數。
需要改變檔案物件指標話話,使用 f.seek(offset, from_what)。指標在該操作中從指定的引用位置移動offset位元,引用位置由 from_what引數指定。from_what 值為 0 表示自檔案起始處開始,1 表示自當前檔案指標位置開始,2 表示自檔案末尾開始。from_what 可以忽略,其預設值為0,此時從檔案頭開始:
>>> 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)跳到末尾處)而且合法的offset 值只能是 f.tell()返回的值或者是零。其它任何offset值都會產生不可預料的行為。
檔案物件還有一些不太常用的附加方法,比如 isatty() 和 truncate() 在庫參考手冊中有檔案物件的完整指南。
使用json 儲存結構化資料
從檔案中讀寫字串很容易。數值就要多費點兒周折,因為read()方法只會返回字串,應將其傳入int() 這樣的函式,就可以將'123'這樣的字串轉換為對應的數值 123。當你想要儲存更為複雜的資料型別,例如巢狀的列表和字典,手工解析和序列化它們將變得更復雜。
Python 允許你使用常用的資料交換格式JSON(JavaScript Object Notation) 。標準模組json 可以接受 Python 資料結構,並將它們轉換為字串表示形式;此過程稱為序列化。從字串表示形式重新構建資料結構稱為反序列化。序列化和反序列化的過程中,表示該物件的字串可以儲存在檔案或資料中,也可以通過網路連線傳送給遠端的機器。
注意:JSON 格式經常用於現代應用程式中進行資料交換。許多程式設計師都已經熟悉。
如果你有一個物件x
,你可以用簡單的一行程式碼檢視其 JSON 字串表示形式:
>>> import json >>> json.dumps([1, 'simple', 'list']) '[1, "simple", "list"]'
dumps() 函式的變種dump() ,直接將物件序列化到檔案物件
json.dump(x, f)
解碼物件,如果f是為讀取而開啟的檔案物件 :
x = json.load(f)
這種簡單的序列化技術可以處理列表和字典,但序列化任意類例項為 JSON 需要額外的努力。json 模組的手冊對此有詳細的描述。
參考資料
- 討論qq群144081101 591302926 567351477 釘釘免費群21745728
- 本文最新版本地址
- 本文涉及的python測試開發庫 謝謝點贊!
- 本文相關海量書籍下載
- 本文原始碼地址
其他
pickle - pickle 模組
與JSON 不同,pickle 是協議,它允許任意複雜的 Python 物件的序列化。因此,它只能用於 Python 而不能用來與其他語言編寫的應用程式進行通訊。預設情況下它也是不安全的:如果資料由熟練的攻擊者精心設計, 反序列化來自不受信任源的 pickle 資料可以執行任意程式碼。
json格式轉換例項
現有 人臉標註的海量資料,部分參見:data
要求輸出:
1,files.txt
image_1515229323784.ir image_1515235832391.ir image_1515208991161.ir image_1515207265358.ir image_1521802748625.ir image_1515387191011.ir ...
2, 座標資訊 poses.txt
檔名、left, top, right, buttom,width,height
image_1515229323784.ir,4,227,234,497,230,270 image_1515235832391.ir,154,89,302,240,148,151 image_1515208991161.ir,76,369,309,576,233,207 image_1515207265358.ir,44,261,340,546,296,285 ...
3,比對檔案:
首先:# 後面的為序列號,從1開始遞增
3 640 480 1及後面3行暫時視為固定。後面一行1 後面為4個座標left, top, right, buttom。
# 1 image_1515229323784.ir 3 640 480 1 0 1 1 4 227 234 497 # 2 image_1515235832391.ir 3 640 480 1 0 1 1 154 89 302 240 # 3 ...
參考程式碼:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import shutil import os import glob import json import pprint import json import data_common directory = 'data' files = data_common.find_files_by_type(directory,'json') i = 1 file_list = [] results = [] poses = [] for filename in files: d = json.load(open(filename)) name = d['image']['rawFilename'].strip('.jpg') pos = d['objects']['face'][0]['position'] num = len(d['objects']['face']) if num > 1: print(filename) print(name) pprint.pprint(d['objects']['face']) out = "# {}\n{}\n3 640 480 1\n0\n{}\n".format(i, name, num) for face in d['objects']['face']: pos = face['position'] top = round(pos['top']) bottom = round(pos['bottom']) left = round(pos['left']) right = round(pos['right']) out = out + "1 {} {} {} {}\n".format(left, top, right, bottom) poses.append("{},{},{},{},{},{},{}".format(name, left, top, right, bottom, right - left, bottom -top)) i = i + 1 #print(out) file_list.append(name) results.append(out.rstrip('\n')) data_common.output_file("files.txt",file_list) data_common.output_file("results.txt",results) data_common.output_file("poses.txt",poses)
習題
1,有關python檔案讀取,哪些描述是錯誤的。
A.f.read(-1)返回整個檔案
B.with中開啟的檔案用完之後要呼叫close()。
C.如果到了檔案末尾,f.read()會返回一個空字串 ('')
D.f.readline()從檔案中讀取單行,字串結尾會自動加上換行符(\r\n)
參考答案: B D
2, open()的模式哪些是錯誤的?
A. rB. r+ C. d D.w+ E.a
參考答案: C D