本篇主要介紹面向?qū)ο蟾呒売梅ㄉ髁辍㈠e誤處理以及文件讀寫。
多繼承
Python 中繼承多個類用逗號隔開喻奥,示例如下所示:
class Dog(Animal, Runnable):
pass
Tips:
- 多重繼承席纽,子類可以獲得父類的所有功能;
- 一般地,Python 中主線都是 單一繼承映凳,若需要 “額外的功能”胆筒,如 Runnable 類似 Java 接口之類的多繼承,把這種設計稱為 MixIn .
- Python 中允許使用多重繼承诈豌,MixIn 是一種常見的設計仆救。
slots
我們知道 Python 中可以給對象動態(tài)添加 屬性字段,如果要限制實例綁定屬性該如何實現(xiàn)呢矫渔?使用 _slot_ 彤蔽,示例代碼如下:
class Student(object):
# 用 tuple 定義允許綁定的屬性名稱
__slots__ = ('name', 'age')
幾點說明:
- 定義 class 時使用特殊變量 slots 限制 class 實例能添加的屬性;
- 若給實例動態(tài)綁定 沒在slots 中聲明的屬性庙洼,會拋出異常:AttributeError顿痪;
- slots 定義的屬性僅對當前類 的實例起作用镊辕,對繼承的子類無用;
- 若在子類中定義 slots 蚁袭,則子類允許定義的屬性就是 自身的slots + 父類的slots .
定制類
定義:類似 實現(xiàn)len() 方法征懈,讓 class 能作用于 len() 函數(shù),像 len() 這樣特殊用途的函數(shù)揩悄,可以定制類卖哎。
常見的有如下幾種函數(shù)來定制類,可當做是重寫了 object 父類的一些方法:
枚舉類
一般地删性,定義常量可以用大寫字母通過整數(shù)定義亏娜,如:JAN = 1,這種寫法簡單蹬挺,但基于類型是 int 型并且仍是變量维贺,值可改變。
未解決上述問題巴帮,為上述枚舉定義一個 class 類型溯泣,每個常量都是 class 的唯一實例。
Python 中提供 Enum 類來實現(xiàn)該功能晰韵。
示例代碼如下:
from enum import Enum, unique
# 1. 定義 Week 枚舉類
Week = Enum('Week', ('Mon', 'Tue', 'Wen', 'Thu', 'Fri', 'Sat', 'Sun'))
# 獲取一個常量
# 打臃⑶恰:Week.Mon = Week.Mon 1
print('Week.Mon =', Week.Mon, Week.Mon.value)
# 枚舉所有成員
for name, member in Week.__members__.items():
print(name, '=>', member, ',', member.value)
# 打印結(jié)果如下:
# Mon => Week.Mon , 1
# Tue => Week.Tue , 2
# Wen => Week.Wen , 3
# Thu => Week.Thu , 4
# Fri => Week.Fri , 5
# Sat => Week.Sat , 6
# Sun => Week.Sun , 7
# 枚舉說明:
# 1) value 屬性時自動賦給成員的 int 常量,默認從 1 開始計數(shù)雪猪;
# 2)若需要更精確地控制枚舉類型栏尚,可以從 Enum 派生出自定義類。
# 2. 自定義枚舉派生類
# 導入 from enum import Enum, unique 只恨,@unique裝飾器可以保證無重復值
@unique
class Weekday(Enum):
Sun = 0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
# 不通方式獲取枚舉常量:一是成員名稱译仗,二是直接根據(jù) value 值獲取。
print('day1 =', Weekday.Mon) # day1 = Weekday.Mon
print('day2 =', Weekday['Tue']) # day2 = Weekday.Tue
print('day3 =', Weekday(3)) # day3 = Weekday.Wed
print('day4.value =', Weekday(4).value) # day4.value = 4
print('day5.value =', Weekday.Fri.value) # day5.value = 5
# 遍歷所有枚舉值
for name, member in Weekday.__members__.items():
print(name, '=>', member)
# 打印結(jié)果如下:
# Sun => Weekday.Sun
# Mon => Weekday.Mon
# Tue => Weekday.Tue
# Wed => Weekday.Wed
# Thu => Weekday.Thu
# Fri => Weekday.Fri
# Sat => Weekday.Sat
總結(jié): Enum 可以把一組相關常量定義在一個 class 中官觅,且 class 不可變纵菌,而且成員可以直接比較。
錯誤&調(diào)試
Python 中使用 try...except...raise...else...finally... 語句進行錯誤處理休涤。先用一段代碼說明如何使用這種錯誤處理機制咱圆。
mport logging
class MyDivideError(ValueError):
pass
def try_test():
try:
print('try...')
r = 10 / 0
print('result:', r)
except ZeroDivisionError as e:
print('catching error:', e)
logging.exception(e)
raise MyDivideError('invalid value: 0')
else:
print('no erro ! will be executed when there are no errors!')
finally:
print('finally... will always be executed whenever catching errors!')
try_test()
# 打印結(jié)果如下:
# try...
# catching error: division by zero
# finally... will always be executed whenever catching errors!
# 異常捕獲后拋出打印結(jié)果:
# __main__.MyDivideError: invalid value: 0
使用說明:
1)try 代碼塊防止代碼出錯,出錯后使用 except 代碼塊捕獲功氨,若沒有錯誤則執(zhí)行 else語句序苏;若想將錯誤拋給外層處理則使用 raise 拋出異常;finally 語句塊不管有沒有發(fā)生錯誤均會執(zhí)行該語句塊捷凄。
2)except 代碼塊同于 catch忱详,若錯誤類型包含父子關系廊遍,則父類會捕獲該錯誤枷踏;所有的錯誤類型都繼承 BaseException。
3)except...else... 發(fā)生了錯誤則執(zhí)行 except 代碼塊及皂,否則執(zhí)行 else 語句偿衰;
4)logging.exception(e) 可以記錄錯誤信息炒刁,便于事后排查仔雷。
單元測試
目前僅以一張簡圖來展示 Python 中單元測試:
IO編程
文件讀寫
背景:在磁盤上讀寫文件的功能均是由操作系統(tǒng)提供冷溶,現(xiàn)代操作系統(tǒng)不允許普通的程序直接操作磁盤。
方式:讀寫文件就是請求操作系統(tǒng)打開一個文件對象(通常稱為文件描述符)佛点,然后醇滥,通過操作系統(tǒng)提供的接口從這個文件對象中讀取數(shù)據(jù)(讀文件)黎比,或者把數(shù)據(jù)寫入該文件對象(寫文件)超营。
- 讀文件
方法: Python內(nèi)置函數(shù) - open(文件名, 標識符['r'只讀])
說明:
1)若文件不存在,該函數(shù)會拋出 IOError 錯誤阅虫,并且給出錯誤碼和詳細信息告知文件不存在演闭;
2)若文件打開成功,使用 read() 函數(shù)可一次性讀取文件全部內(nèi)容颓帝;
3)Python 把內(nèi)容讀到內(nèi)存米碰,用一個 str 對象表示。
4)調(diào)用 close() 方法關閉文件购城。
Tips: 文件使用完畢必須關閉吕座,因為文件對象會占用操作系統(tǒng)的資源,并且os同一時間能打開的文件數(shù)量是有限的瘪板。
# 以下拋出錯誤:FileNotFoundError: [Errno 2] No such file or directory: 'Users/xss/notfound.txt'
file = open('./channel', 'r')
content = file.read()
file.close() # 必須關閉文件
print(content) # 打印文件內(nèi)容(success)
完整定義一個讀文件函數(shù):
def readFile(filename):
try:
file = open(filename, 'r')
print(file.read())
finally:
if file:
file.close()
簡潔代碼寫法:
def readFile2(filename):
with open(filename, 'r') as file:
print(file.read())
問題:當文件size太大時吴趴,一次性讀取文件,內(nèi)存就會爆滿侮攀,如何解決呢锣枝?
方式:保險起見,三種方式:
1)read(size); 每次讀取一行內(nèi)容兰英,每次最多讀取 size 個字節(jié)的內(nèi)容撇叁;
2)readline(); 每次讀取一行內(nèi)容;
3)readlines(); 一次讀取所有內(nèi)容并按行返回 list.
各方式使用場景:
1)read() 適用于文件很小時一次性讀绕杳场陨闹;
2)無法確定文件大小時,反復調(diào)用 read(size) 比較保險薄坏;
3)若是配置文件趋厉,使用 readlines() 最方便。
def readFileByLine(filename):
file = open(filename, 'r')
for line in file.readlines():
print(line.strip()) # 刪除末尾'\n'
- 文件讀取模式
- 文本文件讀取+默認UTF-8: open(filename, 'r') 颤殴;
- 二進制文件讀让倮:open(filename, 'rb') # 二進制文件-圖片視頻等;
- 非UTF-8編碼文件:open(filename, 'r', encoding='gbk') # 中文涵但。
關于文件編碼不規(guī)范問題杈绸,會拋出 UnicodeDecodeError 非法編碼字符帖蔓,使用如下方式:
# f = open('./channel', 'r')
# print(f.read())
ff = open('./first.py', 'r', encoding='gbk', errors='ignore')
print(ff.read()) # 忽略非法字符,讀取中文亂碼(改成 encoding='utf-8')
- 寫文件
open(filename, 'w' / 'wb') 寫文本文件或?qū)懚M制文件
filename = './first.py'
f = open(filename, 'w')
f.write('# Hello, world')
f.close()
readFileByLine(filename)
def writeFile():
with open('./first.py', 'w') as f:
f.write('Hello, world !')
總結(jié): Python 中瞳脓,文件讀寫是通過 open() 函數(shù)打開的文件對象完成的塑娇。使用 with 語句操作文件 IO 是好習慣。
另外還有 StringIO 劫侧、BytesIO埋酬,序列化和JSON內(nèi)置模塊使用,暫用一張圖展示說明: