亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python編程應(yīng)用設(shè)計(jì)原則詳解

 更新時(shí)間:2021年09月14日 14:17:31   作者:somenzz  
什么是好用的代碼呢?其實(shí)就是代碼質(zhì)量比較高,如何評(píng)價(jià)代碼質(zhì)量的高低呢?最常用的、最重要的評(píng)價(jià)標(biāo)準(zhǔn),就是代碼的可維護(hù)性、可讀性、可擴(kuò)展性、靈活性、簡(jiǎn)潔性、可復(fù)用性、可測(cè)試性

寫(xiě)出能用的代碼很簡(jiǎn)單,寫(xiě)出好用的代碼很難。

好用的代碼,也都會(huì)遵循一此原則,這就是設(shè)計(jì)原則,它們分別是:

  • 單一職責(zé)原則 (SRP)
  • 開(kāi)閉原則 (OCP)
  • 里氏替換原則 (LSP)
  • 接口隔離原則 (ISP)
  • 依賴倒置原則 (DIP)

提取這五種原則的首字母縮寫(xiě)詞,就是 SOLID 原則。下面分別進(jìn)行介紹,并展示如何在 Python 中應(yīng)用。

1、單一職責(zé)原則 SRP

單一職責(zé)原則(Single Responsibility Principle)這個(gè)原則的英文描述是這樣的:A class or module should have a single responsibility。如果我們把它翻譯成中文,那就是:一個(gè)類或者模塊只負(fù)責(zé)完成一個(gè)職責(zé)(或者功能)。

讓我們舉一個(gè)更簡(jiǎn)單的例子,我們有一個(gè)數(shù)字 L = [n1, n2, …, nx] 的列表,我們計(jì)算一些數(shù)學(xué)函數(shù)。例如,計(jì)算最大值、平均值等。

一個(gè)不好的方法是讓一個(gè)函數(shù)來(lái)完成所有的工作:

import numpy as np
 
def math_operations(list_):
    # Compute Average
    print(f"the mean is {np.mean(list_)}")
    # Compute Max
    print(f"the max is {np.max(list_)}") 
 
math_operations(list_ = [1,2,3,4,5])
# the mean is 3.0
# the max is 5

實(shí)際開(kāi)發(fā)中,你可以認(rèn)為 math_operations 很龐大,揉雜了各種功能代碼。

為了使這個(gè)更符合單一職責(zé)原則,我們應(yīng)該做的第一件事是將函數(shù) math_operations 拆分為更細(xì)粒度的函數(shù),一個(gè)函數(shù)只干一件事:

def get_mean(list_):
    '''Compute Max'''
    print(f"the mean is {np.mean(list_)}") 
def get_max(list_):
    '''Compute Max'''
    print(f"the max is {np.max(list_)}") 
def main(list_): 
    # Compute Average
    get_mean(list_)
    # Compute Max
    get_max(list_)
main([1,2,3,4,5])
# the mean is 3.0
# the max is 5

這樣做的好處就是:

  • 易讀易調(diào)試,更容易定位錯(cuò)誤。
  • 可復(fù)用,代碼的任何部分都可以在代碼的其他部分中重用。
  • 可測(cè)試,為代碼的每個(gè)功能創(chuàng)建測(cè)試更容易。

但是要增加新功能,比如計(jì)算中位數(shù),main 函數(shù)還是很難維護(hù),因此還需要第二個(gè)原則:OCP。

2、開(kāi)閉原則 OCP

開(kāi)閉原則(Open Closed Principle)就是對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉,這可以大大提升代碼的可維護(hù)性,也就是說(shuō)要增加新功能時(shí)只需要添加新的代碼,不修改原有的代碼,這樣做即簡(jiǎn)單,也不會(huì)影響之前的單元測(cè)試,不容易出錯(cuò),即使出錯(cuò)也只需要檢查新添加的代碼。

上述代碼,可以通過(guò)將我們編寫(xiě)的所有函數(shù)變成一個(gè)類的子類來(lái)解決這個(gè)問(wèn)題。代碼如下:

import numpy as np
from abc import ABC, abstractmethod
class Operations(ABC):
    '''Operations'''
    @abstractmethod
    def operation():
        pass
class Mean(Operations):
    '''Compute Max'''
    def operation(list_):
        print(f"The mean is {np.mean(list_)}") 
class Max(Operations):
    '''Compute Max'''
    def operation(list_):
        print(f"The max is {np.max(list_)}") 
class Main:
    '''Main'''
    def get_operations(list_):
        # __subclasses__ will found all classes inheriting from Operations
        for operation in Operations.__subclasses__():
            operation.operation(list_)
if __name__ == "__main__":
    Main.get_operations([1,2,3,4,5])
# The mean is 3.0
# The max is 5

如果現(xiàn)在我們想添加一個(gè)新的操作,例如:median,我們只需要添加一個(gè)繼承自 Operations 類的 Median 類。新形成的子類將立即被 __subclasses__()接收,無(wú)需對(duì)代碼的任何其他部分進(jìn)行修改。

3、里氏替換原則 (LSP)

里式替換原則的英文是 Liskov Substitution Principle,縮寫(xiě)為 LSP。這個(gè)原則最早是在 1986 年由 Barbara Liskov 提出,他是這么描述這條原則的:

If S is a subtype of T, then objects of type T may be replaced with objects of type S, without breaking the program。

也就是說(shuō) 子類對(duì)象能夠替換程序中父類對(duì)象出現(xiàn)的任何地方,并且保證原來(lái)程序的邏輯行為不變及正確性不被破壞。

實(shí)際上,里式替換原則還有另外一個(gè)更加能落地、更有指導(dǎo)意義的描述,那就是按照協(xié)議來(lái)設(shè)計(jì),子類在設(shè)計(jì)的時(shí)候,要遵守父類的行為約定(或者叫協(xié)議)。父類定義了函數(shù)的行為約定,那子類可以改變函數(shù)的內(nèi)部實(shí)現(xiàn)邏輯,但不能改變函數(shù)原有的行為約定。這里的行為約定包括:函數(shù)聲明要實(shí)現(xiàn)的功能;對(duì)輸入、輸出、異常的約定;甚至包括注釋中所羅列的任何特殊說(shuō)明。

4、接口隔離原則 (ISP)

接口隔離原則的英文翻譯是 Interface Segregation Principle,縮寫(xiě)為 ISP。Robert Martin 在 SOLID 原則中是這樣定義它的:Clients should not be forced to depend upon interfaces that they do not use。

直譯成中文的話就是:客戶端不應(yīng)該被強(qiáng)迫依賴它不需要的接口。其中的 客戶端 ,可以理解為接口的調(diào)用者或者使用者。

舉個(gè)例子:

from abc import ABC, abstractmethod
class Mammals(ABC):
    @abstractmethod
    def swim(self) -> bool:
        pass
    @abstractmethod
    def walk(self) -> bool:
        pass
class Human(Mammals):
    def swim(self)-> bool:
        print("Humans can swim")
        return True 
    def walk(self)-> bool:
        print("Humans can walk")
        return True 
class Whale(Mammals):
     def walk(self) -> bool:
        print("Whales can't walk")
        return False
     def swim(self):
        print("Whales can swim")
        return True 
human = Human()
human.swim()
human.walk()
whale = Whale()
whale.swim()
whale.walk()
 

執(zhí)行結(jié)果:

Humans can swim
Humans can walk
Whales can swim
Whales can't walk

事實(shí)上,子類鯨魚(yú)不應(yīng)該依賴它不需要的接口 walk,針對(duì)這種情況,就需要對(duì)接口進(jìn)行拆分,代碼如下:

from abc import ABC, abstractmethod
class Swimer(ABC): 
    @abstractmethod
    def swim(self) -> bool:
        pass
class Walker(ABC):
    @abstractmethod
    def walk(self) -> bool:
        pass
class Human(Swimer,Walker):
    def swim(self)-> bool:
        print("Humans can swim")
        return True
    def walk(self)-> bool:
        print("Humans can walk")
        return True
class Whale(Swimer):
    def swim(self):
        print("Whales can swim")
        return True
human = Human()
human.swim()
human.walk()
whale = Whale()
whale.swim()

5、依賴反轉(zhuǎn)原則 (DIP)

依賴反轉(zhuǎn)原則的英文翻譯是 Dependency Inversion Principle,縮寫(xiě)為 DIP。英文描述:High-level modules shouldn't depend on low-level modules. Both modules should depend on abstractions. In addition, abstractions shouldn't depend on details. Details depend on abstractions。

我們將它翻譯成中文,大概意思就是:高層模塊不要依賴低層模塊。高層模塊和低層模塊應(yīng)該通過(guò)抽象(abstractions)來(lái)互相依賴。除此之外,抽象不要依賴具體實(shí)現(xiàn)細(xì)節(jié),具體實(shí)現(xiàn)細(xì)節(jié)依賴抽象。

在調(diào)用鏈上,調(diào)用者屬于高層,被調(diào)用者屬于低層,我們寫(xiě)的代碼都屬于低層,由框架來(lái)調(diào)用。在平時(shí)的業(yè)務(wù)代碼開(kāi)發(fā)中,高層模塊依賴低層模塊是沒(méi)有任何問(wèn)題的,但是在框架層面設(shè)計(jì)的時(shí)候,就要考慮通用性,高層應(yīng)該依賴抽象的接口,低層應(yīng)該實(shí)現(xiàn)對(duì)應(yīng)的接口。如下圖所示:

也就是說(shuō)本來(lái) ObjectA 依賴 ObjectB,但為了擴(kuò)展后面可能會(huì)有 ObjectC,ObjectD,經(jīng)常變化,因此為了頻繁改動(dòng),讓高層模塊依賴抽象的接口 interface,然后讓 ObjectB 也反過(guò)來(lái)依賴 interface,這就是依賴反轉(zhuǎn)原則。

舉個(gè)例子,wsgi 協(xié)議就是一種抽象接口,高層模塊有 uWSGI,gunicorn等,低層模塊有 Django,F(xiàn)lask 等,uWSGI,gunicorn 并不直接依賴 Django,F(xiàn)lask,而是通過(guò) wsgi 協(xié)議進(jìn)行互相依賴。

依賴倒置原則概念是高層次模塊不依賴于低層次模塊??此圃谝蟾邔哟文K,實(shí)際上是在規(guī)范低層次模塊的設(shè)計(jì)。低層次模塊提供的接口要足夠的抽象、通用,在設(shè)計(jì)時(shí)需要考慮高層次模塊的使用種類和場(chǎng)景。明明是高層次模塊要使用低層次模塊,對(duì)低層次模塊有依賴性?,F(xiàn)在反而低層次模塊需要根據(jù)高層次模塊來(lái)設(shè)計(jì),出現(xiàn)了「倒置」的顯現(xiàn)。

這樣設(shè)計(jì)好處有兩點(diǎn):

  • 低層次模塊更加通用,適用性更廣
  • 高層次模塊沒(méi)有依賴低層次模塊的具體實(shí)現(xiàn),方便低層次模塊的替換

最后的話

我去年(2020)年 2 月 3 號(hào)購(gòu)買(mǎi)的《設(shè)計(jì)模式之美》專欄,將近一年半才把它學(xué)習(xí)完,再回看之前的代碼,真是一堆垃圾。之前一天寫(xiě)完的代碼,重構(gòu)差不多花了一個(gè)星期,重構(gòu)之后,感覺(jué)還可以再重構(gòu)的更好,似乎無(wú)止境,正如小爭(zhēng)哥說(shuō)的那樣,項(xiàng)目無(wú)論大小,都可以有技術(shù)含量,所謂代碼細(xì)節(jié)是魔鬼,細(xì)節(jié)到處都存在在取舍,應(yīng)該怎么樣,不應(yīng)該怎么樣,都大有學(xué)問(wèn)。

以上就是Python編程應(yīng)用設(shè)計(jì)原則詳解的詳細(xì)內(nèi)容,更多關(guān)于Python編程應(yīng)用設(shè)計(jì)原則的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 淺談Pytorch中的torch.gather函數(shù)的含義

    淺談Pytorch中的torch.gather函數(shù)的含義

    今天小編就為大家分享一篇淺談Pytorch中的torch.gather函數(shù)的含義,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-08-08
  • Matplotlib中文亂碼的3種解決方案

    Matplotlib中文亂碼的3種解決方案

    當(dāng)我們用matplotlib作圖時(shí),往往會(huì)發(fā)現(xiàn)中文的文字變成了小方塊,我在繪制決策樹(shù)的時(shí)候就碰到了這個(gè)問(wèn)題。下面這篇文章主要給大家總結(jié)介紹了關(guān)于Matplotlib中文亂碼的3種解決方案,需要的朋友可以參考下
    2018-11-11
  • 如何用Python識(shí)別車(chē)牌的示例代碼

    如何用Python識(shí)別車(chē)牌的示例代碼

    車(chē)牌識(shí)別系統(tǒng)計(jì)算機(jī)視頻圖像識(shí)別技術(shù)在車(chē)輛牌照識(shí)別中的一種應(yīng)用,本文主要介紹了如何用Python識(shí)別車(chē)牌的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • 整理Python 常用string函數(shù)(收藏)

    整理Python 常用string函數(shù)(收藏)

    這篇文章主要介紹了整理Python 常用string函數(shù)(收藏)的相關(guān)資料,具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-05-05
  • Python自動(dòng)化之批量處理工作簿和工作表

    Python自動(dòng)化之批量處理工作簿和工作表

    今天給大家整理了如何使用Python實(shí)現(xiàn)批量處理工作簿和工作表,文中有非常詳細(xì)的介紹及代碼示例,對(duì)小伙伴們很有幫助,需要的朋友可以參考下
    2021-06-06
  • Python基于checksum計(jì)算文件是否相同的方法

    Python基于checksum計(jì)算文件是否相同的方法

    這篇文章主要介紹了Python基于checksum計(jì)算文件是否相同的方法,涉及Python針對(duì)二進(jìn)制文件的讀取與判定技巧,需要的朋友可以參考下
    2015-07-07
  • Python如何獲取Win7,Win10系統(tǒng)縮放大小

    Python如何獲取Win7,Win10系統(tǒng)縮放大小

    這篇文章主要介紹了Python如何獲取Win7,Win10系統(tǒng)縮放大小,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Python遍歷指定文件及文件夾的方法

    Python遍歷指定文件及文件夾的方法

    這篇文章主要介紹了Python遍歷指定文件及文件夾的方法,對(duì)比兩種實(shí)現(xiàn)技巧分析了Python遍歷文件及文件夾的方法,需要的朋友可以參考下
    2015-05-05
  • Pytorch中的自動(dòng)求梯度機(jī)制和Variable類實(shí)例

    Pytorch中的自動(dòng)求梯度機(jī)制和Variable類實(shí)例

    今天小編就為大家分享一篇Pytorch中的自動(dòng)求梯度機(jī)制和Variable類實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-02-02
  • Python使用matplotlib.pyplot畫(huà)熱圖和損失圖的代碼詳解

    Python使用matplotlib.pyplot畫(huà)熱圖和損失圖的代碼詳解

    眾所周知,在完成論文相關(guān)工作時(shí)畫(huà)圖必不可少,如損失函數(shù)圖、熱力圖等是非常常見(jiàn)的圖,在本文中,總結(jié)了這兩個(gè)圖的畫(huà)法,下面給出了完整的代碼,開(kāi)箱即用,感興趣的同學(xué)可以自己動(dòng)手嘗試一下
    2023-09-09

最新評(píng)論