91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

python的單一職責原則怎么實現

發布時間:2022-03-09 13:43:34 來源:億速云 閱讀:177 作者:iii 欄目:開發技術

今天小編給大家分享一下python的單一職責原則怎么實現的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    一,封裝

    封裝是面向對象編程思想的重要特征之一。

    (一)什么是封裝

    封裝是一個抽象對象的過程,它容納了對象的屬性和行為實現細節,并以此對外提供公共訪問。

    這樣做有幾個好處:

    • 分離使用與實現。可直接使用公共接口,但不需要考慮它內部具體怎么實現。

    • 擁有內部狀態隱藏機制,可實現信息/狀態隱藏。

    (二)封裝與訪問

    就面向對象編程來說,類就是實現對象抽象的手段,封裝的實現,就是將對象的屬性與行為抽象為類中屬性與方法。

    舉個例子:

    對象 AudioFile ,需要有文件名,還需要能播放與停止播放。用類封裝的話,就類似于下面這個實現:

    class AudioFil:
        def __init__(self, filename):
            self.filename = filename
        def play(self):
            print("playing...")
        def stop(self):
            print("stop playing...")

    self參數必須是傳入類方法的第一個(最左側)參數;Python 會通過這個參數自動填入實例對象(也就是調用這個方法的主體)。這個參數不必叫self,其位置才是重點(C++或Java程序員可能更喜歡把它稱作this,因為在這些語言中,該名稱反應的是相同的概念。在Python中,這個參數總是需要明確的)。

    封裝之后,能輕松實現訪問:

    if __name__ == "__main__":
        file_name = "金剛葫蘆娃.mp3"
        current_file = AudioFil(filename=file_name)
        print(current_file.filename)
        current_file.play()
        current_file.stop()
    >>>
    金剛葫蘆娃.mp3
    playing 金剛葫蘆娃.mp3...
    stop playing 金剛葫蘆娃.mp3...

    同時能在外部修改內部的屬性:

    if __name__ == "__main__":
        file_name = "金剛葫蘆娃.mp3"
        current_file = AudioFil(filename=file_name)
        print(current_file.filename)
        current_file.play()
        current_file.stop()
        current_file.filename = "舒克與貝塔.ogg"
        print(current_file.filename)
        current_file.play()
        current_file.stop()
    >>>
    金剛葫蘆娃.mp3
    playing 金剛葫蘆娃.mp3...
    stop playing 金剛葫蘆娃.mp3...
    舒克與貝塔.ogg
    playing 舒克與貝塔.ogg...
    stop playing 舒克與貝塔.ogg...

    (三)私有化與訪問控制

    盡管能通過外部修改內部的屬性或狀態,但有時出于安全考慮,需要限制外部對內部某些屬性或者方法的訪問。

    一些語言能顯式地指定內部屬性或方法的有效訪問范圍。比如在 Java 中明確地有 publicprivate 等關鍵字提供對內部屬性與方法的訪問限制,但 python 并提供另一種方式將它們的訪問范圍控制在類的內部:

    • _ 或 __來修飾屬性與方法,使之成為內部屬性或方法。

    • 用 __method-name__ 來實現方法重載。

    1,屬性與方法的私有化

    舉個例子:

    class AudioFil:
        def __init__(self, filename):
            self._filename = filename
        def play(self):
            print(f"playing {self._filename}...")
        def stop(self):
            print(f"stop playing {self._filename}...")
    
    if __name__ == "__main__":
        file_name = "金剛葫蘆娃.mp3"
        current_file = AudioFil(filename=file_name)
        print(current_file._filename)
        current_file.play()
        current_file.stop()

    python的單一職責原則怎么實現

    注意 _filename 的格式,單下劃線開頭表明這是一個類的內部變量,它提醒程序員不要在外部隨意訪問這個變量,盡管是能夠訪問的。

    更加嚴格的形式是使用雙下劃線:

    class AudioFil:
        def __init__(self, filename):
            self.__filename = filename
        def play(self):
            print(f"playing {self.__filename}...")
        def stop(self):
            print(f"stop playing {self.__filename}...")
    
    if __name__ == "__main__":
        file_name = "金剛葫蘆娃.mp3"
        current_file = AudioFil(filename=file_name)
        print(current_file.__filename)	#AttributeError: 'AudioFil' object has no attribute '__filename'
        current_file.play()
        current_file.stop()

    注意 __filename 的格式,雙下劃線開頭表明這是一個類的內部變量,它會給出更加嚴格的外部訪問限制,但還是能夠通過特殊手段實現外部訪問:

        # print(current_file.__filename)
        print(current_file._AudioFil__filename)

    _ClassName__attributename

    總之,這種私有化的手段“防君子不防小人”,更何況這并非是真的私有化——偽私有化。有一個更加準確的概念來描述這種機制:變量名壓縮。

    2,變量名壓縮

    Python 支持變量名壓縮(mangling,起到擴展作用)的概念——讓類內某些變量局部化。

    壓縮后的變量名通常會被誤認為是私有屬性,但這其實只是一種把類所創建的變量名局部化的方式而已:名稱壓縮并無法阻止類外代碼對它的讀取。

    這種機制主要是為了避免實例內的命名空間的沖突,而不是限制變量名的訪問。因此,壓縮過的變量名最好稱為“偽私有”,而不是“私有”。

    類內部以 _ 或 __ 開頭進行命名的操作只是一個非正式的慣例,目的是讓程序員知道這是一個不應該修改的名字(它對Python自身來說沒有什么意義)。

    3,方法重載

    python 內置的數據類型自動地支持有些運算操作,比如 + 運算、索引、切片等,它們都是通過對應對象的類的內部的以 __method-name__ 格式命名的方法來實現的。

    方法重載可用于實現模擬內置類型的對象(例如,序列或像矩陣這樣的數值對象),以及模擬代碼中所預期的內置類型接口。

    最常用的重載方法是__init__構造方法,幾乎每個類都使用這個方法為實例屬性進行初始化或執行其他的啟動任務。

    方法中特殊的self參數和__init__構造方法是 Python OOP的兩個基石

    舉個例子:

    class AudioFil:
        def __init__(self, filename):
            self.__filename = filename
        def __str__(self):
            return f"我是《{self.__filename}》"
        def play(self):
            print(f"playing {self.__filename}...")
        def stop(self):
            print(f"stop playing {self.__filename}...")
    
    if __name__ == "__main__":
        file_name = "金剛葫蘆娃.mp3"
        current_file = AudioFil(filename=file_name)
        print(current_file)		#>>> 我是《金剛葫蘆娃.mp3》

    (四)屬性引用:getter、setter 與 property

    一些語言使用私有屬性的方式是通過 getter 與 setter 來實現內部屬性的獲取與設置。python 提供 property 類來達到同樣的目的。舉個例子:

    class C:
        def __init__(self):
            self._x = None
        def getx(self) -> str:
            return self._x
        def setx(self, value):
            self._x = value
        def delx(self):
            del self._x
        x = property(getx, setx, delx, "I'm the 'x' property.")
    
    if __name__ == '__main__':
        c = C()
        c.x = "ccc" # 調用setx
        print(c.x)  # 調用getx
        del c.x     # 調用delx

    property的存在讓對屬性的獲取、設置、刪除操作自動內置化。

    更加優雅的方式是使用@property裝飾器。舉個例子:

    class C:
        def __init__(self):
            self._x = None
        @property
        def x(self):
            """I'm the 'x' property."""
            return self._x
        @x.setter
        def x(self, value):
            self._x = value
        @x.deleter
        def x(self):
            del self._x
    
    if __name__ == '__main__':
        c = C()
        c.x = "ccc"
        print(c.x)  
        del c.x

    二,單一職責原則

    (一)一個不滿足單一職責原則的例子

    現在需要處理一些音頻文件,除了一些描述性的屬性之外,還擁有播放、停止播放和信息存儲這三項行為:

    class AudioFile:
        def __init__(self, filename, author):
            self.__filename = filename
            self.__author = author
            self.__type = self.__filename.split(".")[-1]
        def __str__(self):
            return f"我是《{self.__filename}》"
        def play(self):
            print(f"playing {self.__filename}...")
        def stop(self):
            print(f"stop playing {self.__filename}...")
        def save(self, filename):
            content = {}
            for item in self.__dict__:
                key = item.split("__")[-1]
                value = self.__dict__[item]
                content[key] = value
            with open(filename+".txt", "a") as file:
                file.writelines(str(content)+'\n')
    
    if __name__ == '__main__':
        file_name = "金剛葫蘆娃.mp3"
        author_name = "姚禮忠、吳應炬"
        current_file = AudioFile(filename=file_name,author=author_name)
        current_file.save(filename="info_list")

    這個類能夠正常工作。

    注意觀察 save 方法,在保存文件信息之前,它做了一些格式化的工作。顯然后面的工作是“臨時添加”的且在別的文件類型中可能也會用到。
    隨著項目需求的變更或者其他原因,經常會在方法內部出現這種處理邏輯的擴散現象,即完成一個功能,需要新的功能作為前提保障。

    從最簡單的代碼可重用性的角度來說,應該將方法內可重用的工作單獨提出來:

    至于公共功能放在哪個層次,請具體分析。

    def info_format(obj):
        content = {}
        for item in obj.__dict__:
            key = item.split("__")[-1]
            value = obj.__dict__[item]
            content[key] = value
        return content
    class AudioFile:
        ...
        def save(self, filename):
            content = info_format(self)
            with open(filename+".txt", "a") as file:
                file.writelines(str(content)+'\n')

    但是,給改進后的代碼在遇到功能變更時,任然需要花費大力氣在原有基礎上進行修改。比如需要提供信息搜索功能,就可能出現這種代碼:

    class AudioFile:
        ...
        def save(self, filename):
            ...
        def search(self, filename, key=None):
            ...

    如果后期搜索條件發生變更、或者再新增功能,都會導致類內部出現功能擴散,將進一步增加原有代碼的復雜性,可讀性逐漸變差,尤其不利于維護與測試。

    (二)單一職責原則

    單一職責原則(Single-Responsibility Principle,SRP)由羅伯特·C.馬丁于《敏捷軟件開發:原則、模式和實踐》一書中提出。這里的職責是指類發生變化的原因,單一職責原則規定一個類應該有且僅有一個引起它變化的原因,否則類應該被拆分。

    該原則提出對象不應該承擔太多職責,如果一個對象承擔了太多的職責,至少存在以下兩個缺點:

    • 一個職責的變化可能會削弱或者抑制這個類實現其他職責的能力;

    • 當客戶端需要該對象的某一個職責時,不得不將其他不需要的職責全都包含進來,從而造成冗余代碼或代碼的浪費。

    舉個例子:一個編譯和打印報告的模塊。想象這樣一個模塊可以出于兩個原因進行更改。

    首先,報告的內容可能會發生變化。其次,報告的格式可能會發生變化。這兩件事因不同的原因而變化。單一職責原則說問題的這兩個方面實際上是兩個獨立的職責,因此應該在不同的類或模塊中。

    總之,單一職責原則認為將在不同時間因不同原因而改變的兩件事情結合起來是一個糟糕的設計。

    看一下修改后的代碼:

    class AudioFile:
        def __init__(self, filename, author):
            self.__filename = filename
            self.__author = author
            self.__type = self.__filename.split(".")[-1]
        def __str__(self):
            return f"我是《{self.__filename}》"
        def play(self):
            print(f"playing {self.__filename}...")
        def stop(self):
            print(f"stop playing {self.__filename}...")
    
    class AudioFileDataPersistence:
        def save(self, obj, filename):
            ...
    class AudioFileDataSearch:
        def search(self, key, filename):
            ...
    
    if __name__ == '__main__':
        file_name = "金剛葫蘆娃.mp3"
        author_name = "姚禮忠、吳應炬"
        current_file = AudioFile(filename=file_name, author=author_name)
        data_persistence = AudioFileDataPersistence()
        data_persistence.save(current_file, filename="info_list")
        data_search = AudioFileDataSearch()
        data_search.search(file_name, filename="info_list")

    但這樣將拆分代碼,是不是合理的選擇?

    三,封裝與單一職責原則

    從封裝的角度看來說,它的目的就是在對外提供接口的同時,提高代碼的內聚性和可重用性,但功能大而全的封裝更加的不安全。

    單一職責原則通過拆分代碼實現更低的耦合性和更高的可重用性,但過度拆分會增加對象間交互的復雜性。

    關于兩這的結合,有一些問題需要事先注意:

    • 需求的粒度是多大?

    • 維護的成本有多高?

    作為面向對象編程的基礎概念與實踐原則,二者實際上是因果關系——如果一個類是有凝聚力的,如果有一個更高層次的目的,如果它的職責符合它的名字,那么 SRP 就會自然而然地出現。SRP 只是代碼優化后的實際的結果,它本身并不是一個目標。

    以上就是“python的單一職責原則怎么實現”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    志丹县| 商洛市| 武山县| 黄梅县| 阆中市| 兴宁市| 抚顺市| 阿勒泰市| 苗栗县| 永兴县| 安新县| 马山县| 和田县| 徐州市| 锦屏县| 瓦房店市| 湘潭县| 三台县| 马边| 历史| 临潭县| 巴楚县| 万源市| 山东| 定边县| 年辖:市辖区| 明水县| 浙江省| 龙山县| 邵武市| 兴城市| 淳化县| 剑河县| 抚顺县| 古蔺县| 南安市| 枣强县| 库尔勒市| 东山县| 博罗县| 巴林左旗|