錯誤、異常和文件
1. 異常處理
錯誤指的是代碼有語法問題,無法解釋運行,必須改正后才能運行
如果代碼沒有語法問題,可以運行,但會出運行時的錯誤,例如除零錯誤,下標越界等問題,這種在運行期間檢測到的錯誤被稱為異常 ,出現了異常必須處理否則程序會終止執行,用戶體驗會很差。Phthon支持程序員自己處理檢測到的異常。可以使用try-except語句進行異常的檢測和處理
1.1 try-except語句
語法:try:【代碼塊A】 #可能會出錯誤的代碼 ? 異常檢測except Exception1[ as e]: ? #異常處理【代碼塊1】 #異常處理代碼 ? ? ? except Exception2[ as e]: ? #異常處理【代碼塊2】 #異常處理代碼....except Exceptionn[ as e]: ? #異常處理【代碼塊n】 #異常處理代碼[else:] ? ? ? ? ? ? ? #可選,如果沒有引發異常會執行處理語句 ? ? ? [finally:] ? ? ? ? ? ? #無論如何都要執行的語句處理語句【后續語句】
-
執行流程:
-
1、首先執行try中【代碼塊A】,如果出現異常,立即終止代碼執行,轉而到except塊中進行異常處理
-
2、異常處理except模塊可以多個,從上往下匹配,如果能夠匹配成功,立即執行相應的異常處理代碼塊,執行完畢后,不在往下匹配,轉到3執行
-
3、執行異常處理完畢后,如果有finally字句則執行finally字句,如果沒有則執行【后續語句】
-
4、如果匹配不到異常,有finally則執行finally,然后則拋出錯誤,終止程序執行。
-
5、如果沒有異常,如果有else字句則執行else字句,執行完else后,有finally字句則執行,沒有則執行【后續語句】
-
-
注意事項:
-
except匹配順序從上到下
-
except語句書寫要求:精確的類型往前放,模糊的,不精確的往后放
-
except不帶任何類型,則匹配所有類型異常,應該放到最后,吞掉異常
-
可以將多種異常用元組的方式(異常類型1,異常類型2...異常類型n)書寫,簡化代碼
-
except字句中e,是一個對象,打印它,會顯示異常信息描述
-
try-except也可以捕獲方法或函數中拋出的異常
-
所有異常類型都繼承自BaseException,使用BaseException可以將異常一網打盡
-
finally字句中可以進行一些清理工作,比如關閉文件,數據庫等工作
-
1.3 拋出異常
手動拋出一個指定類型的異常,無論是哪種異常類都可以帶一個字符串參數,對異常進行描述。
-
raise不帶參數會把錯誤原樣拋出
try:raise ZeroDivisionError('除0錯誤')# raise ZeroDivisionError #如果不想獲取錯誤信息,可以不帶參數
except ZeroDivisionError as e:print(e) #除0錯誤
1.4 異常嵌套
在try塊和excep塊中還可以分別再嵌套try-except塊
1.5 assert斷言
語法:assert 條件 [,異常描述字符串]
執行流程:如果條件為假,則拋出AssertionError,條件為真,就當assert不存在
作用:對于可能出問題的代碼,加上斷言,方便問題排查
print('start')
num = int(input('請輸入一個1~9的整數:'))
assert 0 <num <=9,'num不在1~9'
print('end')
1.6 自定義異常類
如果系統異常類型滿足不了業務需求,那么可以自己定義異常類來處理。
-
自己定義的異常類必須繼承BaseException或Exception
-
步驟:
-
在自定義異常類的構造函數中,調用父類構造函數
-
重寫
__str__
方法輸出異常信息 -
編寫異常處理方法處理異常
-
class CustomError(BaseException): #繼承BaseExceptiondef __init__(self,msg):super().__init__() #調用父類初始化self.msg = msg#重寫__str__,輸出異常信息def __str__(self):return self.msg#3.自定義異常處理方法def handle_exception(self):print('異常處理')try:raise CustomError('自定義異常')
except CustomError as e:print(e)
?
2. 文件處理
文件的處理包括讀文件和寫文件,讀寫文件就是請求操作系統打開一個文件對象,然后,通過操作系統提供的接口從這個文件對象中讀取數據(讀文件),或者把數據寫入這個文件對象(寫文件)。
2.1 文件讀取
文件讀取可分為以下步驟:
-
打開文件
-
讀取文件內容
-
關閉文件
打開文件要使用open內建函數:
open(file [, mode='r', encoding=None, errors=None])
參數說明: file:文件路徑,可以是相對路徑和絕對路徑
mode:文件打開模式
encodeing: 文件編碼方式,不用于二進制文件,一般是utf-8,gbk
errors:指定如何處理編碼和解碼錯誤 ,適用于文本文件
返回值:一個可迭代的文件對象
mode | 解釋 |
---|---|
r | 只讀 |
w | 只寫,寫之前會清空文件的內容,如果文件不存在,會創建新文件 |
a | 追加的方式,在原本內容中繼續寫,如果文件不存在,則會創建新文件 |
r+ | 可讀可寫 |
w+ | 打開一個文件用于讀寫。如果該文件已存在則將其覆蓋。如果該文件不存在,創建新文件。 |
a+ | 打開一個文件用于讀寫。如果該文件已存在,文件指針將會放在文件的結尾。文件打開時會是追加模式。如果該文件不存在,創建新文件用于讀寫。 |
b | rb、wb、ab、rb+、wb+、ab+意義和上面一樣,用于二進制文件操作 |
注意:二進制文件一般用于視頻、音頻、圖片
讀取文件常用函數:
函數 | 解釋 |
---|---|
read([size]) | 讀取文件(讀取size字符,默認讀取全部) |
readline([size]) | 讀取一行,如果指定size,將讀入指定的字符數 |
readlines() | 把文件內容按行全部讀入,返回一個包含所有行的列表 |
#打開文件
fp = open('qfile.txt','r',encoding='utf-8')
?
#讀取文件全部內容
#content = fp.read() ?
#print(content)
?
#讀取指定字符數,包括行尾的換行符\n
# print(fp.read(20))
?
#讀取一行
# print(fp.readline(5)) #讀取指定字符數
# print(fp.readline()) #讀取一整行,直到碰到一個\n
?
#讀取所有行,返回列表
# print(fp.readlines()) ?
?
#關閉文件
fp.close()
#由于文件讀寫時都有可能產生IOError,一旦出錯,后面的f.close()就不會調用。
# 所以,為了保證無論是否出錯都能正確地關閉文件,我們可以使用try ... finally來實現:
# try:
# ? ? fp = open('qfile.txt','r',encoding='utf-8')
# ? ? print(fp.readlines())
# finally:
# ? ? fp.close()
#可以簡寫為:
#with語句會自動調用close方法關閉文件
with open('qfile.txt','r',encoding='utf-8') as fp:print(fp.readline())
#fread()和freadlines()會一次讀入文件全部內容,如果文件太大,會直接耗盡內存的,因為文件對象可迭代,所以可以用for循環遍歷文件讀取
with open('qfile.txt','r',encoding='utf-8') as fp:for line in fp:print(line.strip()) ? #注意無論是read、readline、readlines都會讀入行末的\n,所以需要手動剔除\n
2.2 寫文件
path = "file11.txt"
?
#1.打開文件
f = open(path,"w",encoding="utf-8")
?
#2.寫入內容,將內容寫入到緩沖區
#不會自動換行,需要換行的話,需要在字符串末尾添加換行符
f.write("Whatever is worth doing is worth doing well該行很驕傲很關鍵\n")
?
?
#3.刷新緩沖區【加速數據的流動,保證緩沖區的流暢】
f.flush()
?
#4.關閉文件 關閉文件也會刷新緩沖區
f.close()
?
#簡寫方式:可以不用手動調用close
with open(path,"w",encoding="utf-8") as f1:f.write("Whatever is worth doing is worth doing well該行很驕傲很關鍵")
?
2.3 移動文件指針
文件是順序向后讀寫的,如果想要移動文件指針,可以使用seek方法:
file_obj.seek(offset,whence=0)
功能:移動文件指針
參數:offset 是偏移量,正數表示從文件開頭向文件末尾移動,負數相反。
whence : 文件指針的位置,可選參數,值可以是
SEEK_SET or 0 表示文件開頭位置,是默認值
SEEK_CUR or 1 表示當前位置(不能使用)
SEEK_END or 2 文件末尾位置(不能使用)
返回值:無
#1.txt內容:hello world
with open('1.txt','r',encoding='utf-8') as fp:fp.seek(5) #移動到hello后的空格位置print(fp.read(3)) #wofp.seek(0) ? #移動到開頭print(fp.read(5)) #helloprint(fp.tell()) ? #tell()顯示當前指針位置
3.CSV文件操作
逗號分隔值(Comma-Separated Values,CSV),其文件以純文本形式存儲表格數據(數字和文本),文件的每一行都是一個數據記錄。每個記錄由一個或多個字段組成,用逗號分隔。使用逗號作為字段分隔符是此文件格式的名稱的來源,因為分隔字符也可以不是逗號,有時也稱為字符分隔值。
在Windows下,csv文件可以通過記事本,excel,notepad++,editplus等打開
-
作用:CSV廣泛用于不同體系結構的應用程序之間交換數據表格信息,解決不兼容數據格式的互通問題。
-
需要導入csv模塊
3.1 讀取csv
import csv
with open(r'csv\winequality-red.csv') as fp: #1.打開文件#delimiter指定分隔符csv_reader = csv.reader(fp,delimiter=';') #2.獲取csv讀取器header = next(csv_reader) #獲取第一行的標題print(header)for line in csv_reader: #3.遍歷所有的行print(line)
3.2 寫入csv
import csv
l1 = [[1,2,3],[4,5,6],[7,8,9]]
#打開文件時,要添加newline=''參數,否則會多一個空行
with open('1.csv','w',newline='') as fp: #1.打開文件#delimiter='\t'指定數據分隔符csv_writer = csv.writer(fp,delimiter='\t') #2.獲取writerfor line in l1:csv_writer.writerow(line) #3.寫入文件