'''
作者:韭白
源自:
https://www.cnblogs.com/shockerli/p/python-study-note.html
'''
SyntaxError 類表示語法錯誤,當解釋器發現代碼無法通過語法檢查時會觸發的錯誤。語法錯誤是無法用 try...except...捕獲的。
>>> print:
File "<stdin>", line 1
print:
^
SyntaxError: invalid syntax
即便程序的語法是正確的,在運行它的時候,也有可能發生錯誤。運行時發生的錯誤被稱為異常。
錯誤信息的前面部分顯示了異常發生的上下文,並以調用棧的形式顯示具體信息。
>>> 1 + '0'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Python 提供了 try ... except ... 的語法結構來捕獲和處理異常。
try 語句執行流程大致如下:
st=>start: try 子句
cond_has_error=>condition: 是否有異常
cond_has_else=>condition: 是否有 else 子句
cond_has_finally=>condition: 是否有 finally 子句
io=>inputoutput: verification
op_except=>operation: except 子句處理異常
op_else=>operation: 執行 else 子句
op_finally=>operation: 執行 finally 子句
e=>end: 結束
st->cond_has_error
cond_has_error(yes, right)->op_except->cond_has_else
cond_has_error(no)->cond_has_else
cond_has_else(yes, right)->op_else->cond_has_finally
cond_has_else(no)->cond_has_finally
cond_has_finally(yes, right)->op_finally->e
cond_has_finally(no)->e
首先,執行 try 子句(在關鍵字 try 和關鍵字 except 之間的語句)
如果沒有異常發生,忽略 except 子句,try 子句執行後結束。
如果在執行 try 子句的過程中發生了異常,那麼 try 子句餘下的部分將被忽略。如果異常的類型和 except 之後的名稱相符,那麼對應的 except 子句將被執行。最後執行 try 語句之後的代碼。
如果一個異常沒有與任何的 except 匹配,那麼這個異常將會傳遞給上層的 try 中。
一個 try 語句可能包含多個 except 子句,分別來處理不同的特定的異常。
最多只有一個 except 子句會被執行。
處理程序將只針對對應的 try 子句中的異常進行處理,而不是其他的 try 的處理程序中的異常。
一個 except 子句可以同時處理多個異常,這些異常將被放在一個括號裡成為一個元組。
最後一個 except 子句可以忽略異常的名稱,它將被當作通配符使用。可以使用這種方法列印一個錯誤信息,然後再次把異常拋出。
try except 語句還有一個可選的 else 子句,如果使用這個子句,那麼必須放在所有的 except 子句之後。這個子句將在 try 子句沒有發生任何異常的時候執行。
異常處理並不僅僅處理那些直接發生在 try 子句中的異常,而且還能處理子句中調用的函數(甚至間接調用的函數)裡拋出的異常。
不管 try 子句裡面有沒有發生異常,finally 子句都會執行。
如果一個異常在 try 子句裡(或者在 except 和 else 子句裡)被拋出,而又沒有任何的 except 把它截住,那麼這個異常會在 finally 子句執行後再次被拋出。
拋出異常使用 raise 語句拋出一個指定的異常。
raise 唯一的一個參數指定了要被拋出的異常。它必須是一個異常的實例或者是異常的類(也就是 Exception 的子類)。
如果你只想知道這是否拋出了一個異常,並不想去處理它,那麼一個簡單的 raise 語句就可以再次把它拋出。
自定義異常可以通過創建一個新的異常類來擁有自己的異常。異常類繼承自 Exception 類,可以直接繼承,或者間接繼承。
當創建一個模塊有可能拋出多種不同的異常時,一種通常的做法是為這個包建立一個基礎異常類,然後基於這個基礎類為不同的錯誤情況創建不同的子類。
大多數的異常的名字都以"Error"結尾,就跟標準的異常命名一樣。
實例import sys
class Error(Exception):
"""Base class for exceptions in this module."""
pass
class InputError(Error):
"""Exception raised for errors in the input.
Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
try:
print('code start running...')
raise InputError('input()', 'input error')
int('a')
s = 1 + 'a'
dit = {'name': 'john'}
print(dit['1'])
except InputError as ex:
print("InputError:", ex.message)
except TypeError as ex:
print('TypeError:', ex.args)
pass
except (KeyError, IndexError) as ex:
"""支持同時處理多個異常, 用括號放到元組裡"""
print(sys.exc_info())
except:
"""捕獲其他未指定的異常"""
print("Unexpected error:", sys.exc_info()[0])
raise RuntimeError('RuntimeError')
else:
"""當無任何異常時, 會執行 else 子句"""
print('"else" 子句...')
finally:
"""無論有無異常, 均會執行 finally"""
print('finally, ending')
open() 函數用於打開/創建一個文件,並返回一個 file 對象:
open(filename, mode)
文件打開模式:
r以只讀方式打開文件。文件的指針將會放在文件的開頭。這是默認模式。rb以二進位格式打開一個文件用於只讀。文件指針將會放在文件的開頭。r+打開一個文件用於讀寫。文件指針將會放在文件的開頭。rb+以二進位格式打開一個文件用於讀寫。文件指針將會放在文件的開頭。w打開一個文件只用於寫入。如果該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。wb以二進位格式打開一個文件只用於寫入。如果該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。w+打開一個文件用於讀寫。如果該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。wb+以二進位格式打開一個文件用於讀寫。如果該文件已存在則打開文件,並從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。a打開一個文件用於追加。如果該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容之後。如果該文件不存在,創建新文件進行寫入。ab以二進位格式打開一個文件用於追加。如果該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容之後。如果該文件不存在,創建新文件進行寫入。a+打開一個文件用於讀寫。如果該文件已存在,文件指針將會放在文件的結尾。文件打開時會是追加模式。如果該文件不存在,創建新文件用於讀寫。ab+以二進位格式打開一個文件用於追加。如果該文件已存在,文件指針將會放在文件的結尾。如果該文件不存在,創建新文件用於讀寫。文件對象方法fileObject.close()
close() 方法用於關閉一個已打開的文件。關閉後的文件不能再進行讀寫操作,否則會觸發 ValueError 錯誤。 close() 方法允許調用多次。
當 file 對象,被引用到操作另外一個文件時,Python 會自動關閉之前的 file 對象。 使用 close() 方法關閉文件是一個好的習慣。
fileObject.flush()
flush() 方法是用來刷新緩衝區的,即將緩衝區中的數據立刻寫入文件,同時清空緩衝區,不需要是被動的等待輸出緩衝區寫入。
一般情況下,文件關閉後會自動刷新緩衝區,但有時你需要在關閉前刷新它,這時就可以使用 flush() 方法。
fileObject.fileno()
fileno() 方法返回一個整型的文件描述符(file descriptor FD 整型),可用於底層作業系統的 I/O 操作。
fileObject.isatty()
isatty() 方法檢測文件是否連接到一個終端設備,如果是返回 True,否則返回 False。
next(iterator[,default])
Python 3 中的 File 對象不支持 next() 方法。 Python 3 的內置函數 next() 通過迭代器調用 __next__() 方法返回下一項。在循環中,next() 函數會在每次循環中調用,該方法返回文件的下一行,如果到達結尾(EOF),則觸發 StopIteration。
fileObject.read()
read() 方法用於從文件讀取指定的字節數,如果未給定或為負則讀取所有。
fileObject.readline()
readline() 方法用於從文件讀取整行,包括 "\n" 字符。如果指定了一個非負數的參數,則返回指定大小的字節數,包括 "\n" 字符。
fileObject.readlines()
readlines() 方法用於讀取所有行(直到結束符 EOF)並返回列表,該列表可以由 Python 的 for... in ... 結構進行處理。如果碰到結束符 EOF,則返回空字符串。
fileObject.seek(offset[, whence])
seek() 方法用於移動文件讀取指針到指定位置。
whence 的值, 如果是 0 表示開頭, 如果是 1 表示當前位置, 2 表示文件的結尾。whence 值為默認為0,即文件開頭。例如:
seek(x, 0):從起始位置即文件首行首字符開始移動 x 個字符
seek(x, 1):表示從當前位置往後移動 x 個字符
seek(-x, 2):表示從文件的結尾往前移動 x 個字符
fileObject.tell(offset[, whence])
tell() 方法返回文件的當前位置,即文件指針當前位置。
fileObject.truncate([size])
truncate() 方法用於從文件的首行首字符開始截斷,截斷文件為 size 個字符,無 size 表示從當前位置截斷;截斷之後 V 後面的所有字符被刪除,其中 Widnows 系統下的換行代表2個字符大小。
fileObject.write([str])
write() 方法用於向文件中寫入指定字符串。
在文件關閉前或緩衝區刷新前,字符串內容存儲在緩衝區中,這時你在文件中是看不到寫入的內容的。
如果文件打開模式帶 b,那寫入文件內容時,str (參數)要用 encode 方法轉為 bytes 形式,否則報錯:TypeError: a bytes-like object is required, not 'str'。
fileObject.writelines([str])
writelines() 方法用於向文件中寫入一序列的字符串。這一序列字符串可以是由迭代對象產生的,如一個字符串列表。換行需要指定換行符 \n。
實例filename = 'data.log'
with open(filename, 'w+', encoding='utf-8') as file:
print('文件名稱: {}'.format(file.name))
print('文件編碼: {}'.format(file.encoding))
print('文件打開模式: {}'.format(file.mode))
print('文件是否可讀: {}'.format(file.readable()))
print('文件是否可寫: {}'.format(file.writable()))
print('此時文件指針位置為: {}'.format(file.tell()))
num = file.write("第一行內容\n")
print('寫入文件 {} 個字符'.format(num))
print(file.readline(), file.tell())
file.seek(0)
print(file.readline(), file.tell())
file.write('第二次寫入的內容\n')
print(file.readline(), file.tell())
file.seek(0)
print(file.read(9))
file.seek(0)
print(file.readlines())
file.seek(0)
for line in file:
print(line, end='')
if not file.closed:
file.close()
輸出:
文件名稱: data.log
文件編碼: utf-8
文件打開模式: w+
文件是否可讀: True
文件是否可寫: True
此時文件指針位置為: 0
寫入文件 6 個字符
16
第一行內容
16
41
第一行內容
第二次
['第一行內容\n', '第二次寫入的內容\n']
第一行內容
第二次寫入的內容
序列化
在 Python 中 pickle 模塊實現對數據的序列化和反序列化。pickle 支持任何數據類型,包括內置數據類型、函數、類、對象等。
方法dump將數據對象序列化後寫入文件
pickle.dump(obj, file, protocol=None, fix_imports=True)
必填參數 obj 表示將要封裝的對象。
必填參數 file 表示 obj 要寫入的文件對象,file 必須以二進位可寫模式打開,即wb。
可選參數 protocol 表示告知 pickle 使用的協議,支持的協議有 0,1,2,3,默認的協議是添加在 Python 3 中的協議3。
從文件中讀取內容並反序列化
pickle.load(file, fix_imports=True, encoding='ASCII', errors='strict')
必填參數 file 必須以二進位可讀模式打開,即rb,其他都為可選參數。
dumps以字節對象形式返回封裝的對象,不需要寫入文件中
pickle.dumps(obj, protocol=None, fix_imports=True)
loads從字節對象中讀取被封裝的對象,並返回
pickle.loads(bytes_object, fix_imports=True, encoding='ASCII', errors='strict')
實例import pickle
data = [1, 2, 3]
dumps_obj = pickle.dumps(data)
print('pickle.dumps():', dumps_obj)
loads_data = pickle.loads(dumps_obj)
print('pickle.loads():', loads_data)
filename = 'data.log'
with open(filename, 'wb') as file:
pickle.dump(data, file)
with open(filename, 'rb') as file:
load_data = pickle.load(file)
print('pickle.load():', load_data)
輸出:
pickle.dumps(): b'\x80\x03]q\x00(K\x01K\x02K\x03e.'
pickle.loads(): [1, 2, 3]
pickle.load(): [1, 2, 3]
Python 之父 Guido 推薦的規範
Moduleslower_with_under_lower_with_underPackageslower_with_under一份來自谷歌的 Python 風格規範:
http://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_style_rules/
參考資料