第五天 函數(shù)和面向?qū)ο?2)
今天主要學(xué)習(xí)面向?qū)ο蟮娜筇卣鳎悍庋b、繼承、多態(tài)以及簡單的設(shè)計(jì)模式和模塊化。學(xué)習(xí)項(xiàng)目及練習(xí)源碼地址:GitHub源碼
面向?qū)ο蟮娜筇卣?/h2>
object類
object類是所有類的父類,因此所有的類都有object類的屬性和方法。類定義中沒有指定父類,則默認(rèn)父類是object類。
封裝
隱藏對象的屬性和實(shí)現(xiàn)細(xì)節(jié),外提供必要的方法。相當(dāng)于將“細(xì)節(jié)封裝起來”,只對外暴露“相關(guān)調(diào)用方法”。通過Python的“私有屬性、私有方法”的方式,來實(shí)現(xiàn)“封裝”。Python沒有嚴(yán)格的語法級別的“訪問控制符”,更多的是依靠程序員自覺實(shí)現(xiàn)。
繼承
繼承可以讓子類具有父類的特性,提高了代碼的重用性。
從設(shè)計(jì)上是一種增量進(jìn)化,原有父類設(shè)計(jì)不變的情況下,可以增加新的功能,或者改進(jìn)已有的算法(重寫也叫重載父類的方法)。
-
語法
class 子類類名(父類 1[,父類 2,...]): 類體 定義子類時(shí),必須在其構(gòu)造函數(shù)中調(diào)用父類的構(gòu)造函數(shù)。
子類繼承了父類除構(gòu)造方法之外的所有成員(包括屬性和方法)。
子類可以重新定義父類中的方法,這樣就會覆蓋父類的方法,也稱為“重寫“
子類中可以通過super關(guān)鍵字調(diào)用父類的方法
可以使用類方法mro()或類屬性mro獲取其層次
內(nèi)置函數(shù)dir(),可以方便的看到指定對象所有的屬性和方法
對象方法:__str__()用于返回一個(gè)對于“對象的描述”,對應(yīng)于內(nèi)置函數(shù)str(),內(nèi)置函數(shù)print()就是調(diào)用對象的這個(gè)方法的返回值。
-
看語法,Python是支持多重繼承的
class Parent: def __init__(self,name): self.name = name print("call parent init.") def say_name(self): print('My Name Is:',self.name) class Children(Parent): def __init__(self,name,age): self.age = age Parent.__init__(self,name) # 此處不可以用super().__init__代替 def say_age(self): print("I am a children,my age is:",self.age) def say_name(self): print("I am a children,my name is:",self.name) p = Parent("父親") c = Children("孩子",18) p.say_name() c.say_name() c.say_age() print(p) print(c) print(type(p)) print(type(c)) print(Children.mro()) ''' 輸出結(jié)果如下: call parent init. call parent init. My Name Is: 父親 I am a children,my name is: 孩子 I am a children,my age is: 18 <__main__.Parent object at 0x10bf69ed0> <__main__.Children object at 0x10bfcb1d0> <class '__main__.Parent'> <class '__main__.Children'> [<class '__main__.Children'>, <class '__main__.Parent'>, <class 'object'>] '''
多態(tài)
多態(tài)(polymorphism)是指同一個(gè)方法調(diào)用由于對象不同可能會產(chǎn)生不同的行為。
多態(tài)是方法的多態(tài),屬性沒有多態(tài)
-
多態(tài)的存在有 2 個(gè)必要條件:繼承、方法重寫。
class Car: def __init__(self): print('make a car') def honk(self): print('喇叭滴滴滴') class BWM(car): def __init__(self): print('make a BWM car') Car.__init__(self) def honk(self): print('寶馬來了請閃開') class BYD(Car): def __init__(self): print('make a BYD car') Car.__init__(self) def honk(self): print('BYD正在向你靠近') def honk(car): if isinstance(car,Car): car.honk() else: print("沒車別嗶嗶嗶") bwm = BWM() byd = BYD() honk(bwm) honk(byd) honk(None)
簡單的設(shè)計(jì)模式
什么是設(shè)計(jì)模式?
前人總結(jié)的一系列解決各種場景問題的套路。
工廠模式
顧名思義:所謂工廠模式就是一個(gè)對象根據(jù)調(diào)用參數(shù)的不同,可以生產(chǎn)許多不同的對象。
class StarFactory:
def __init__(self):
print("歡迎使用明星工廠")
def createStar(self,name):
if name == 'man':
return ManStar()
elif name == "womam":
return WomanStar()
class ManStar:
def __init__(self):
print("我是一名超級男明星")
class WomanStar:
def __init__(self):
print("我是一名超級女明星")
單列模式
單例模式(Singleton Pattern)的核心作用是確保一個(gè)類只有一個(gè)實(shí)例,并且提供一個(gè)訪問該實(shí)例的全局訪問點(diǎn)。單例模式只生成一個(gè)實(shí)例對象,減少了對系統(tǒng)資源的開銷。當(dāng)一個(gè)對象的產(chǎn)生需要比較多的資源,如讀取配置文件、產(chǎn)生其他依賴對象時(shí),可以產(chǎn)生一個(gè)“單例對象”,然后永久駐留內(nèi)存中,從而極大的降低開銷。
使用new方法
-
類實(shí)例對象在Python的模塊時(shí)是天然的單例模式
class Singleton: __obj = None __hasInited = False def __init__(self,name): print("try init....") self.name = name if Singleton.__hasInited == False: Singleton.__hasInited = True def __new__(cls, *args, **kwargs): if cls.__obj == None: cls.__obj = object.__new__(cls) return cls.__obj def say_name(self): print(self.name) a = Singleton("a") b = Singleton("b") print(a) print(b) a.say_name() b.say_name() ''' try init.... try init.... <__main__.Singleton object at 0x10882dad0> <__main__.Singleton object at 0x10882dad0> b 這里不是a,說明第二次改變了第一次對象的值,是一個(gè)坑 b '''
模塊和包
使用模塊化編程便于將一個(gè)任務(wù)分解成多個(gè)模塊,實(shí)現(xiàn)團(tuán)隊(duì)協(xié)同開發(fā),完成大規(guī)模程序。實(shí)現(xiàn)代碼復(fù)用和可維護(hù)性。
模塊
一個(gè)模塊對應(yīng)python源文件,一般后綴名是:.py
-
標(biāo)準(zhǔn)庫模塊
Python 標(biāo)準(zhǔn)庫提供了操作系統(tǒng)功能、網(wǎng)絡(luò)通信、文本處理、文件處理、數(shù)學(xué)運(yùn)算等基 本的功能。比如:random(隨機(jī)數(shù))、math(數(shù)學(xué)運(yùn)算)、time(時(shí)間處理)、file(文件處理)、os(和操作系統(tǒng)交互)、sys(和解釋器交互)等。
第三方模塊
用戶自動(dòng)模塊
導(dǎo)入模塊
-
import語句
import 模塊名 # 導(dǎo)入一個(gè)模塊 import 模塊 1,模塊 2... # 導(dǎo)入多個(gè)模塊 import 模塊名 as 模塊別名 # 導(dǎo)入模塊并使用新名字import加載的模塊分為四個(gè)通用類別:
- 使用 python 編寫的代碼(.py文件);
- 已被編譯為共享庫的C、C++擴(kuò)展;
- 包好一組模塊的包
- 使用C編寫并鏈接到python解釋器的內(nèi)置模塊;
-
from...import
from...import 導(dǎo)入的是模塊中的一個(gè)函數(shù)/一個(gè)類。
動(dòng)態(tài)導(dǎo)入:內(nèi)置函數(shù)__import__()可以實(shí)現(xiàn)動(dòng)態(tài)導(dǎo)入模塊
使用importlib模塊實(shí)現(xiàn)動(dòng)態(tài)導(dǎo)入
-
每個(gè)模塊都有一個(gè)名稱,通過特殊變量name可以獲取模塊的名稱
一般情況下name輸出模塊名字,對應(yīng)源文件名。僅有一個(gè)例外,就是當(dāng)一個(gè)模塊被作為程序入口時(shí)(主程序、交互式提示符下),它的name的值為“__main__”。我們可以根據(jù)這個(gè)特 點(diǎn),將模塊源代碼文件中的測試代碼進(jìn)行獨(dú)立的處理。
-
當(dāng)導(dǎo)入一個(gè)模塊時(shí),模塊中的代碼都會被執(zhí)行。如果再次導(dǎo)入這個(gè)模塊,不會再次執(zhí)行。
import math print(math.__name__)
包
當(dāng)需要把多個(gè)模塊放在一起時(shí),需要就需要用到包了
-
Python中的包就是一個(gè)必須有init.py的目錄
- 作為包的標(biāo)識,不能刪除。
- 用來實(shí)現(xiàn)模糊導(dǎo)入
- 導(dǎo)入包實(shí)質(zhì)是執(zhí)行init.py文件,可以在init.py文件中做這個(gè)包的初始化、以及需要統(tǒng)一執(zhí)行代碼、批量導(dǎo)入。
-
導(dǎo)入包
import 包名.模塊名 import 包名.子包名.模塊名 from 包名.模塊名 import 函數(shù),類,變量 包下面可以包含“模塊(module)”,也可以再包含“子包(subpackage)”
-
如果是子包內(nèi)的引用,可以按相對位置引入子模塊
from .. import 模塊文件名 # 導(dǎo)入上層目錄中的模塊文件 from . import 模塊文件名 # 導(dǎo)入本層目錄的模塊文件 -
sys.path和模塊搜索路徑
當(dāng)導(dǎo)入某個(gè)模塊文件時(shí),Python解釋器一般按照如下路徑尋找模塊文件(按照順序?qū)ふ?,找到即停不繼續(xù)往下尋找):
內(nèi)置模塊
當(dāng)前目錄
程序的主目錄
pythonpath目錄(如果已經(jīng)設(shè)置了pythonpath環(huán)境變量)
標(biāo)準(zhǔn)鏈接庫目錄
第三方庫目錄(site-packages目錄)
-
.pth 文件的內(nèi)容(如果存在的話)
在工程目錄建立這樣一個(gè)文件,一行代表一個(gè)目錄
sys.path.append()臨時(shí)添加的目錄
安裝第三方庫
pip install 模塊名稱
Python的文件操作
文本文件和二進(jìn)制文件
-
文本文件
文本文件存儲的是普通“字符”文本,python默認(rèn)為unicode字符集(兩個(gè)字節(jié)表示一個(gè)字符,最多可以表示:65536個(gè))
-
二進(jìn)制文件
二進(jìn)制文件把數(shù)據(jù)內(nèi)容用“字節(jié)”進(jìn)行存儲
文件操作相關(guān)模塊概述
Python標(biāo)準(zhǔn)庫中提供了如下常用文件操作的庫:
| 名稱 | 說明 |
|---|---|
| io 模塊 | 文件流的輸入和輸出操作 input output |
| os 模塊 | 基本操作系統(tǒng)功能,包括文件操作 |
| glob 模塊 | 查找符合特定規(guī)則的文件路徑名 |
| fnmatch 模塊 | 使用模式來匹配文件路徑名 |
| fileinput 模塊 | 處理多個(gè)輸入文件 |
| filecmp 模塊 | 用于文件的比較 |
| cvs 模塊 | 用于 csv 文件處理 |
| pickle 和 cPickle | 用于序列化和反序列化 |
| xml 包 | 用于 XML 數(shù)據(jù)處理 |
| bz2、gzip、zipfile、zlib、tarfile | 用于處理壓縮和解壓縮文件(分別對應(yīng)不同的算法) |
常用文件操作函數(shù)
-
open()
open(文件名[,打開方式,[encoding="字符編碼"]])打開方式有如下幾種:
模式 描述 r 讀 read 模式 w f = open(r"filepath","w")。寫 write模式。如果文件不存在則創(chuàng)建;如果文件存在,則重寫新內(nèi)容; a 追加 append 模式。如果文件不存在則創(chuàng)建;如果文件存在,則在文件末尾追加內(nèi)容 b 二進(jìn)制 binary 模式(可與其他模式組合使用) + 讀、寫模式(可與其他模式組合使用)
-
close()
打開的文件對象必須顯式調(diào)用 close()方法 關(guān)閉文件對象。當(dāng)調(diào)用 close()方法時(shí),首先會把緩沖區(qū)數(shù)據(jù)寫入文件(也可以直接調(diào)用 flush() 方法),再關(guān)閉文件,釋放文件對象。為了確保打開的文件對象正常關(guān)閉,一般結(jié)合異常機(jī)制的finally或者with關(guān)鍵字實(shí)現(xiàn)無論何種情況都能關(guān)閉打開的文件對象。
-
write(txt)
把字符串txt寫入到文件中
-
writelines(txtList):
把字符串列表寫入文件中,不添加換行符
-
with
with關(guān)鍵字(上下文管理器)可以自動(dòng)管理上下文資源,不論什么原因跳出with塊,都能確保文件正確的關(guān)閉,并且可以在代碼塊執(zhí)行完畢后自動(dòng)還原進(jìn)入該代碼塊時(shí)的現(xiàn)場。
-
read(size)
從文件中讀取 size 個(gè)字符,并作為結(jié)果返回。如果沒有 size 參數(shù),則讀取整個(gè)文件。讀取到文件末尾,會返回空字符串。
-
readline()
讀取一行內(nèi)容作為結(jié)果返回。讀取到文件末尾,會返回空字符串。
readlines()
文件讀寫操作練習(xí):測試代碼
os和os.path模塊
os模塊可以幫助我們直接對操作系統(tǒng)進(jìn)行操作。我們可以直接調(diào)用操作系統(tǒng)的可執(zhí)行文件、命令,直接操作文件、目錄等等
-
os.system
os.system 可以幫助我們直接調(diào)用系統(tǒng)的命令
import os os.system("ping www.google.com") -
os.startfile
直接運(yùn)行可執(zhí)行文件
異常和錯(cuò)誤處理
python中,引進(jìn)了很多用來描述和處理異常的類,稱為異常類。異常類定義中包含了該類異常的信息和對異常進(jìn)行處理的方法。

如何定位異常
當(dāng)發(fā)生異常時(shí),Python解釋器會報(bào)相關(guān)的錯(cuò)誤信息,并會在控制臺打印出相關(guān)錯(cuò)誤信息。只需按照從上到下的順序即可追溯(Trackback)錯(cuò)誤發(fā)生的過程,最終定位引起錯(cuò)誤的那一行代碼。
異常處理語句
-
try...except
try: a = 1/0 except ZeroDivisionError: print("不能除零") except BaseException as e: # 允許多個(gè)錯(cuò)誤捕獲,更好的控制你的程序 print(e) -
else
try: a = 1/1 except ZeroDivisionError: print("不能除零") except BaseException as e: # 允許多個(gè)錯(cuò)誤捕獲,更好的控制你的程序 else: print(a) # try里面的沒有錯(cuò)誤時(shí)執(zhí)行 finally: print("無論如何都要執(zhí)行")# 通常用于釋放系統(tǒng)資源 finally
return語句和異常處理問題
在try....except語句中最好不要用return語句,將它放在try之外。
常見異常匯總
| 異常名稱 | 說明 |
|---|---|
| ArithmeticError | 所有數(shù)值計(jì)算錯(cuò)誤的基類 |
| AssertionError | 斷言語句失敗 |
| AttributeError | 對象沒有這個(gè)屬性 |
| BaseException | 所有異常的基類 |
| DeprecationWarning | 關(guān)于被棄用的特征的警告 |
| EnvironmentError | 操作系統(tǒng)錯(cuò)誤的基類 |
| EOFError | 沒有內(nèi)建輸入,到達(dá) EOF 標(biāo)記 |
| Exception | 常規(guī)錯(cuò)誤的基類 |
| FloatingPointError | 浮點(diǎn)計(jì)算錯(cuò)誤 |
| FutureWarning | 關(guān)于構(gòu)造將來語義會有改變的警告 |
| GeneratorExit | 生成器(generator)發(fā)生異常來通知退出 |
| ImportError | 導(dǎo)入模塊/對象失敗 |
| IndentationError | 縮進(jìn)錯(cuò)誤 |
| IndexError | 序列中沒有此索引(index) |
| IOError | 輸入/輸出操作失敗 |
| KeyboardInterrupt | 用戶中斷執(zhí)行(通常是輸入^C) |
| KeyError | 映射中沒有這個(gè)鍵 |
| LookupError | 無效數(shù)據(jù)查詢的基類 |
| MemoryError | 內(nèi)存溢出錯(cuò)誤(對于 Python 解釋器不是致命的) |
| NameError | 未聲明/初始化對象 (沒有屬性) |
| NotImplementedError | 尚未實(shí)現(xiàn)的方法 |
| OSError | 操作系統(tǒng)錯(cuò)誤 |
| OverflowError | 數(shù)值運(yùn)算超出最大限制 |
| OverflowWarning | 舊的關(guān)于自動(dòng)提升為長整型(long)的警告 |
| PendingDeprecationWarning | 關(guān)于特性將會被廢棄的警告 |
| ReferenceError | 弱引用(Weak reference)試圖訪問已經(jīng)垃圾回收了的對象 |
| RuntimeError | 一般的運(yùn)行時(shí)錯(cuò)誤 |
| RuntimeWarning | 可疑的運(yùn)行時(shí)行為(runtime behavior)的警告 |
| StandardError | 所有的內(nèi)建標(biāo)準(zhǔn)異常的基類 |
| StopIteration | 迭代器沒有更多的值 |
| SyntaxError | Python 語法錯(cuò)誤 |
| SyntaxWarning | 可疑的語法的警告 |
| SystemError | 一般的解釋器系統(tǒng)錯(cuò)誤 |
| SystemExit | 解釋器請求退出 |
| TabError | Tab 和空格混用 |
| TypeError | 對類型無效的操作 |
| UnboundLocalError | 訪問未初始化的本地變量 |
| UnicodeDecodeError | Unicode 解碼時(shí)的錯(cuò)誤 |
| UnicodeEncodeError | Unicode 編碼時(shí)錯(cuò)誤 |
| UnicodeError | Unicode 相關(guān)的錯(cuò)誤 |
| UnicodeTranslateError | Unicode 轉(zhuǎn)換時(shí)錯(cuò)誤 |
| UserWarning | 用戶代碼生成的警告 |
| ValueError | 傳入無效的參數(shù) |
| Warning | 警告的基類 |
| WindowsError | 系統(tǒng)調(diào)用失敗 |
| ZeroDivisionError | 除(或取模)零 (所有數(shù)據(jù)類型) |
自定義異常類
程序開發(fā)中,有時(shí)候我們也需要自己定義異常類。自定義異常類一般都是運(yùn)行時(shí)異常,通常繼承Exception或其子類即可。命名一般以 Error、Exception為后綴。
- 自定義異常由 raise 語句主動(dòng)拋出
- 練習(xí)自定異常源碼
小結(jié)
到目前為止,Python語言的真實(shí)基礎(chǔ)算是告一個(gè)段落。離登堂入室還有半步飛仙的距離了。接下來做的就是實(shí)戰(zhàn)+實(shí)戰(zhàn)+實(shí)戰(zhàn),將所學(xué)的知識融會貫通。之后還有關(guān)于Python高階的學(xué)習(xí),比如并發(fā),異步程序,網(wǎng)絡(luò)編程等等。
GUI實(shí)戰(zhàn)
話說Python搞后臺服務(wù)的較多,但是跨平臺的GUI開發(fā)其實(shí)也不弱,通過幾個(gè)GUI的練習(xí),鞏固一下前面所學(xué)的知識。
常用的GUI庫
-
Tkinter
tkinter(Tk interface)是Python的標(biāo)準(zhǔn)GUI庫,支持跨
平臺的GUI程序開發(fā)。 -
PyQT
PyQt是一個(gè)創(chuàng)建GUI應(yīng)用程序的工具包。它是Python編程語言和Qt庫的成功融合。Qt庫是目前最強(qiáng)大的庫之一。在線指南
-
wxPython
wxPython是Python語言的一套優(yōu)秀的GUI圖形庫,允許Python程序員很方便的創(chuàng)建完整的、功能健全的GUI用戶界面。 wxPython是作為優(yōu)秀的跨平臺GUI庫wxWidgets的Python封裝和Python模塊的方式提供給用戶的。
就如同Python和wxWidgets一樣,wxPython也是一款開源軟件,并且具有非常優(yōu)秀的跨平臺能力,能夠支持運(yùn)行在32 [1] /64位windows、絕大多數(shù)的Unix或類Unix系統(tǒng)、Macintosh OS X下。