Python鞏固

来源:https://www.cnblogs.com/maxdofo/archive/2020/05/20/12920567.html
-Advertisement-
Play Games

PYTHON 補充知識點 面向對象三大特性:封裝,繼承和多態。 繼承的意義在於兩點: 第一,子類如若繼承自父類,則自動獲取父類所有功能,並且可以在此基礎上再去添加自己獨有的功能。 第二,當子類和父類存在同樣方法時,子類的方法覆寫了父類的代碼,於是子類對象執行的將是子類的方法,即“多態”。 多態到底有 ...


PYTHON 補充知識點

面向對象三大特性:封裝,繼承和多態。

繼承的意義在於兩點:

第一,子類如若繼承自父類,則自動獲取父類所有功能,並且可以在此基礎上再去添加自己獨有的功能。

第二,當子類和父類存在同樣方法時,子類的方法覆寫了父類的代碼,於是子類對象執行的將是子類的方法,即“多態”。

多態到底有什麼用呢?在繼承關係里,子類對象的數據類型也可以被當作父類的數據類型,但是反過來不行。那麼當我們編寫一個函數,參數需要傳入某一個類型的對象時,我們根本不需要關心這個對象具體是哪個子類,統統按照基類來處理,而具體調用誰的重載函數,再具體根據對象確切類型來決定:

class Animal():
    def get_name(self):
        print("animal")

class Dog(Animal):
    def get_name(self):
        print("dog")

class Cat(Animal):
    def get_name(self):
        print("cat")

def run(animal):  # 待執行的函數。
    animal.get_name()

cat = Cat()
run(cat)
dog = Dog()
run(dog)

>>>cat
>>>dog

當我們再新增子類rabbit,wolf等時,根本不需要改變run函數。這就是著名的開閉原則:即對擴展開放(增加子類),對修改關閉(不需要改變依賴父類的函數參數)

多態存在的三個必要條件:繼承,重寫,父類引用指向子類對象。

對於靜態語言來說,需要傳入參數類型,那麼實參則必須是該類型或者子類才可以。而對於動態語言(比如python)來說,甚至不需要非得如此,只需要這個類型裡面有個get_name方法即可。這就是動態語言的鴨子特性:只要走路像鴨子,就認為它是鴨子!”這樣的話,多態的實現甚至可以不要求繼承。

裝飾器的使用

裝飾器的本質就是一個Python函數,它可以在其他函數不做任何代碼變化的前提下增強額外功能。裝飾器也返回一個函數對象。當我們想給很多函數額外添加功能,給每一個添加太麻煩時,就可以使用裝飾器。

比如有幾個函數想給它們添加一個“輸出函數名稱的功能”:

def test():
    print("this is test")
    print(test.__name__)

test()

但是如果還有其他函數也需要這個功能,那麼就要每個都添加一個print,這樣代碼非常冗雜。這時候就可以使用裝飾器。

def log(func):
    def wrapper(*args,**kwargs):
        print(func.__name__)
        return func(*args,**kwargs)
    return wrapper

@log  # 裝飾器
def test():
    print("this is test")

test()

當把@log加到test的定義處時相當於執行了:

test = log(test)

於是乎再執行test()其實就wrapper(),可以得到原本函數的功能以及新添加的功能,非常方便。

還可以定義一個帶參數的裝飾器,這給裝飾器帶來了更大的靈活性:

def log(text):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(text)
            return func(*args, **kwargs)
        return wrapper
    return decorator

@log("ahahahahaha")  # 帶參數的裝飾器
def test():
    print("this is test")

這樣就相當於執行了:

test = log("ahahahahaha")(test)

還有一點,雖然裝飾器非常方便,但是這樣使用會導致test的原信息丟失(比如上面的代碼test.__name__會變成"wrapper"而不是"test")。這樣的話需要導入一個functool包,然後在wrapper函數前面加上一句@functools.wraps(func)就可以了:

def log(text):
    def decorator(func):
        @functools.wraps(func)  # 加上一句
        def wrapper(*args, **kwargs):
            print(text)
            return func(*args, **kwargs)
        return wrapper
    return decorator

@log("ahahahahaha")
def test():
    print("this is test")

最後,如果一個函數使用多個裝飾器進行裝飾的話,則需要根據邏輯確定裝飾順序。

Python中的多繼承與MRO

Python是允許多繼承的(即一個子類有多個父類)。多重繼承的作用主要在於給子類拓展功能:比如dog和cat都是mamal類的子類,它們擁有mamal的功能,如果想給它們添加“runnable”的功能,只需要再繼承一個類runnable即可。這個額外功能的類一般都會加一個“Mixin”尾碼作為區分,表示這個類是拓展功能用的:

class Dog(mamal,RunableMixIn,CarnivorousMixIn)
    pass

使用Mixin的好處在於不用設計複雜的繼承關係即可拓展類的功能。

多繼承會產生一個問題:如果同時有多個父類都實現了一個方法,那麼子類應該調用誰的方法呢?這就涉及到MRO(方法解析順序)。

在Python3之後,MRO使用的都是C3演算法(不區分經典類和新式類,全部都是新式類)。C3演算法首先使用深度優先演算法,先左後右,得到搜索路徑後,只保留“好的結點”。好的結點指的是:該節點之後沒有任何節點繼承自這個節點。
比如說下圖:
c3
按照深度優先,從左至右的順序應該是F,A,Y,X,B,Y,X。其中第一個Y和第一個X後面B也繼承自Y,X,於是把它們去掉,最終路徑是:F,A,B,Y,X

在MRO中,使用super方法也要註意:假設有類A,B,C,A繼承自B和C。如果B中使用了Super重寫了一個方法,這個方法會在C中去尋找(儘管C並不是B的父類):

class B:
    def log(self):
        print("log B")

    def go(self):
        print("go B")
        super(B, self).go()
        self.log()

class C:

    def go(self):
        print("go C")


class A(B, C):

    def log(self):
        print("log A")
        super(A,self).log()


if __name__ == "__main__":
    a = A()
    # 1.a對象執行go,先找自己有沒有go,自己沒有按照MRO去找B
    # 2.B中找到了go並執行,super順位查找到c的go,執行。
    # 3.然後執行self.log,因為self此時是A對象,於是首先找到A中的log函數執行
    # 4.再次執行super函數,此時順位查找到B,執行B.log
    a.go()  

"結果"
go B
go C
log A
log B

進程與線程

以前的單核CPU也可以進行多任務,方法是任務1一會兒,任務2一會兒,任務3一會兒......因為CPU速度很快,所以看起來像是執行了多任務,其實就是交替執行任務。

真正的並行需要在多核CPU上進行。但實際開發中的任務數量一定比核數量要多,所以每個核依舊是在交替執行任務。

進程:對於操作系統來說,一個任務就是一個“進程”,打開一個文件,程式等都是打開一個“進程”。

當一個程式在硬碟上運行起來,會在記憶體中形成一個獨立的記憶體體,這個記憶體體中有自己獨立的地址空間,有自己的堆。操作系統會以進程為最小的資源分配單位。

線程:線程是操作系統調度執行的最小單位。有時一個進程會有多個子任務:比如一個word文件它同時進行打字、編排、拼寫檢查等任務,這些子任務被稱為“線程”。每個進程至少要有一個線程,和進程一樣,真正的多線程只能依靠多核CPU來實現。

進程與線程的區別:進程是擁有資源的獨立單位,線程不擁有系統資源,但可以訪問自己所隸屬的進程的資源。在系統開銷方面,進程的創建與撤銷都需要系統都要為之分配和回收資源,它的開銷要比線程大。

多進程的優點是穩定性高,因為一個進程掛了,其他進程還可以繼續工作。(主進程不能掛,但是由於主進程負責分配任務,所以掛的概率很低)。而線程呢,由於多線程共用一個進程的記憶體,所以一個線程掛了全體一起掛。並且多線程在操作共用資源時容易出錯(死鎖等問題)

一個線程只能屬於一個進程,而一個進程可以有多個線程,但至少有一個線程;
資源分配給進程,同一進程的所有線程共用該進程的所有資源;
處理機分給線程,即真正在處理機上運行的是線程;
線程在執行過程中,需要協作同步。不同進程的線程間要利用消息通信的辦法實現同步

無論是多進程還是多線程,一旦任務數量多了效率都會急劇下降,因為切換任務不僅僅是直接去執行就好了,這中間還需要保存現場、創建新環境等一系列操作,如果任務數量一多會有很多時間浪費在這些準備工作上面。


實現多任務主要有三種辦法:

  1. 多個進程,每個進程僅有一個線程
  2. 一個進程,進程中有多個線程
  3. 多進程多線程(過於複雜,不推薦)


同時執行多個任務的時候,任務之間是要互相協調的,有時任務2必須要等任務1結束之後去執行,有時任務3和4不能同時執行......所以多進程和多線程編寫架構要相對更複雜。


任務類型主要分為IO密集型計算密集型”。計算密集型任務主要是需要大量計算,比如計算圓周率,對視頻解碼等。計算密集型任務主要消耗的是CPU資源(不適合Python這種運算效率低的腳本語言編寫代碼,適合C語言);而IO密集型任務主要是IO操作,CPU消耗很少,大部分時間都消耗在等待IO。(適合開發效率高的腳本語言)

對於計算密集型任務來說,如果多進程多線程任務遠遠大於核數,那麼效率反而會急劇下降;而對於IO密集型任務來說,多進程多線程可能會好一些,但還是不夠好。

利用非同步IO可以實現單進程單線程執行多任務。利用非同步IO可以顯著提升操作系統的調度效率。對應到Python語言,非同步IO被稱為協程。

協程:比線程更加輕量級的“微線程”,協程不被操作系統內核管理,而是由用戶自己執行。這樣的好處就是極大的提升了調度效率,不會像線程那樣切換浪費資源。

子程式在所有語言里都是層級調用(棧實現),即A調用B,B又調用C,C完了B完了最後A才能完。一個線程就是調用一個子程式。而協程不同,用戶可以任意在執行A時暫停去執行B,過一會兒再來執行A。

協程的優勢在於:由於是程式自己控制子程式切換,所以相比線程可以節省大量不必要的切換,對於IO密集型任務來說協程更優。而且不需要線程的鎖機制。

協程是在單線程上執行的,那麼如何利用多核CPU呢?方法就是多進程+協程。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Java Web系列之使用Eclipse開發web項目(jsp項目) ...
  • web前端一定要這樣學,才會事半功倍! 如果你是想要學習web前端的新人,那麼恭喜你,看完這篇文章,儘早的選擇好努力的方向和規劃好自己的學習路線,比別人多一點付出並且持之以恆,你就已經贏在了起跑線上。有道是,莫道君行早,更有早行人。 如果你已經學完了但是還沒找到工作,那麼就應該反省一下自己,到底哪些 ...
  • 有這樣一個場景:如果你在登錄之前輸入了http://localhost:8080/oauth2-mgm-app/#/userManage,想進入userManage頁面,但是由於沒有登錄,系統是不會讓你進入這個頁面,之後會被定向到login頁面。但是在登錄之後,認為你有這個許可權了,就需要重新定向到u ...
  • "TOC" JSP JSP:動態網頁 靜態和動態: 1. 不能和是否有“動感”混為一談 2. 是否隨著時間,地點,用戶操作而改變 動態網頁需要使用到服務端腳本語言(JSP) 架構 架構: 1. BS:網頁端 服務端 1. 如網頁版:京東、百度 2. 客戶端不需要升級 3. 維護方便 4. 不需要安裝 ...
  • 「蒲公英」期刊,每周更新,我們專註於挖掘「 基礎技術 、 工程化 、 跨端框架技術 、 圖形編程 、 服務端開發 、 桌面開發 、 人工智慧 」等多個大方向的業界熱點,並加以專業的解讀;不僅如此,我們還精選凹凸技術文章,向大家呈現團隊內的研究技術方向。 抬頭仰望,蒲公英的種子會生根發芽,如夏花絢爛; ...
  • 北航OO(2020)第三單元博客作業 [TOC] JML語言總結 理論基礎 JML是用於對Java程式進行規格化設計的一種表示語言,它使用JavaDoc註釋的方式來表示規格。JML以Java語法為基礎併進行了一定的擴充。JML的語法分為幾個層次,下麵對JML Level 0的核心特性進行簡要的總結。 ...
  • 背景 最近一口氣看完了Joshua Bloch大神的 Effective Java (下文簡稱EJ)。書中以tips的形式羅列了Java開發中的最佳實踐,每個tip都將其意圖和要點壓縮在了標題里,這種做法我很喜歡:一來比較親切,比起難啃的系統書,EJ就像是一本Java的《俚語指南》;二來記憶起來十分 ...
  • 發版流程 SNAPSHOT(快照版)--->M1(里程碑1)--->M2--->M3--->RC1(候選版本1)--->RC2--->Release(正式版)--->SR1(正式版第一次修複)--SR2--->SR3 選擇SR2版本之後的版本比較合適。之前的會有很多坑 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...