Python中的對象行為與特殊方法(二)類型檢查與抽象基類

来源:http://www.cnblogs.com/linxiyue/archive/2017/12/12/8025871.html
-Advertisement-
Play Games

類型檢查 創建類的實例時,該實例的類型為類本身: 要測試實例是否屬於某個類,可以使用type()內置函數: 當然,python中不建議如此檢查,更好的辦法是使用內置類型檢查函數isinstance(obj, cls): 同樣的,內置函數issubclass(cls1, cls2)可以用做子類的檢查: ...


類型檢查

創建類的實例時,該實例的類型為類本身:

class Foo(object):
    pass

f = Foo()

要測試實例是否屬於某個類,可以使用type()內置函數:

>>> type(f) == Foo
True

當然,python中不建議如此檢查,更好的辦法是使用內置類型檢查函數isinstance(obj, cls):

>>> isinstance(f, Foo)
True

同樣的,內置函數issubclass(cls1, cls2)可以用做子類的檢查:

class SubFoo(Foo):
    pass

>>> issubclass(SubFoo, Foo)
True

這兩個內置函數的第二個參數可以是一個單獨的類,也可以是幾個類的元組:

>>> isinstance(1, (str, int))
True

以下兩個特殊方法可用於重新定義這兩個內置函數:

__instancecheck__(cls, obj)

__subclasscheck__(cls, subcls)

鴨子類型

python是門動態語言,調用對象的時候是不用考慮對象的類型的,而只需要對象有某些特定的屬性或者行為即可,也就是鴨子類型。

為了保持程式的鬆散耦合,我們可以不用繼承,而只是模仿一些對象的行為:

class File(object):
    def open(self):
        print 'open File'


class FileLike(object):
    def open(self):
        print 'open FileLike'

        
def foo(f):
    f.open()

只要定義了open()方法的實例,就可以作為函數foo()的參數:

>>> f = File()
>>> fl = FileLike()
>>> foo(f)
open File
>>> foo(fl)
open FileLike

當我們測試對象是否可以作為foo()的參數時,要同時進行兩次isinstance()類型檢查,如果類型更多的話呢?

現在我們可以將File和FileLike分組並對其進行一次類型檢查:

class FileLikeClass(object):
    def __init__(self):
        self.reg = set()
        
    def register(self, cls):
        self.reg.add(cls)

    def __instancecheck__(self, obj):
        return self.__subclasscheck__(type(obj))

    def __subclasscheck__(self, subcls):
        return any(cls in self.reg for cls in subcls.mro())


flc = FileLikeClass()
flc.register(File)
flc.register(FileLike)

上述代碼使用FileLikeClass創造一個對象,將要檢查的類型放入對象的一個集合屬性中,然後重新定義__instancecheck__(cls, obj)與__subclasscheck__(cls, subcls)方法,

進行子類檢查時,會檢查子類及子類的基類是否在集合中,進行類型檢查時,會檢查對象的類型是否是集合中的類的子類:

>>> f = File()
>>> isinstance(f, flc)
True
>>> fl = FileLike()
>>> isinstance(fl, flc)
True

當然,python提供了一種更正式的機制來分組對象,定義介面併進行類型檢查----抽象基類

抽象基類

要定義抽象基類,需要使用abc模塊,該模塊定義一個元類(ABCMeta)和兩個裝飾器(@abstractmethod,抽象方法)與(@abstractproperty, 抽象特性),使用方法如下:

from abc import ABCMeta, abstractmethod, abstractproperty

class AbsFile(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def open(self):
        pass

抽象基類就是定義各種方法而不做具體實現的類,抽象基類是無法實例化的:

>>> AbsFile()
TypeError: Can't instantiate abstract class AbsFile with abstract methods open

任何繼承自抽象基類的類也必須實現這些方法,否則無法實例化:

class File(AbsFile):
    pass

實例化失敗:

>>> File()
TypeError: Can't instantiate abstract class File with abstract methods open

需定義open方法:

class File(AbsFile):
    def open(self):
        print 'open File'

當然抽象基類中也可以對抽象方法進行具體實現,在子類中可以通過super()來調用:

class AbsFile(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def open(self):
        print 'open AbsFile'
    

class File(AbsFile):
    def open(self):
        super(File, self).open()
        print 'open File'

實例化:

>>> File().open()
open AbsFile
open File

如果只想執行類型檢查的話,可以使用register()方法:

from abc import ABCMeta, abstractmethod, abstractproperty

class AbsFile(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def open(self):
        pass
    

class File(object):
    pass

AbsFile.register(File)

向抽象基類註冊某個類時,是不會檢查該類是否實現了抽象基類的抽象方法或者特性的,只會影響類型檢查:

>>> f = File()
>>> isinstance(f, AbsFile)
True

python的collections模塊定義了與序列,集合和字典有關的各種抽象基類,numbers模塊定義了與數字有關的抽象基類。


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

-Advertisement-
Play Games
更多相關文章
  • 本文同時發表在 "https://github.com/zhangyachen/zhangyachen.github.io/issues/125" 假設我們有如下結構體: 我們需要對結構體內的欄位進行驗證合法性: Id的值在某一個範圍內。 Name的長度在某一個範圍內。 Email格式正確。 我們可 ...
  • 本文同時發表在 "https://github.com/zhangyachen/zhangyachen.github.io/issues/123" 寫一下fopen/getc/putc等C庫的粗略實現,參考了K&R,但是有幾點根據自己理解的小改動,下麵再具體說一下^_^ 寫這篇文章主要是幫助自己理解 ...
  • Infi-chu: http://www.cnblogs.com/Infi-chu/ 模塊:difflib 安裝:Python版本大於等於2.3系統自帶 功能:對比文本之間的差異,而且支持輸出可讀性比較強的HTML文檔,與Linux中的diff命令比較相似。 兩個字元串的差異對比: 此外diffli ...
  • 第一階段:一年之內的 JAVA 從業人員 這個階段是你成長極快的階段,而且你可能會經常加班。但是加班不代表你就可以鬆懈了,永遠記得我說的那句話,從你入行那一刻起,你就要不停的學習。在這一年裡,你至少需要看完《 Java 編程思想》這本書。這本書的內容是幫助你對於 Java 有一個更加深入的瞭解,是 ...
  • 1、Java開發環境概述 JDK:Java開發工具包(Java Development Kit),包括java編譯器、java運行時環境和常用的類庫; JRE:Java運行時環境(Java Runtime Environment)。 2、跨平臺特性 ①平臺指的是操作系統(Windows,Linux, ...
  • 如果上一篇我轉發的關於ubuntu的博文,你看完覺得還沒準備好,那麼,本篇從最基礎的開始,安裝虛擬機到正常使用ubuntu 虛擬機 1.什麼是虛擬機 虛擬機(Virtual Machine)指通過軟體模擬的具有完整硬體系統功能的、運行在一個完全隔離環境中的完整電腦系統。 通俗的說,我們平常看得見摸 ...
  • 題目描述 如題,已知一個數列,你需要進行下麵兩種操作: 1.將某一個數加上x 2.求出某區間每一個數的和 輸入輸出格式 輸入格式: 第一行包含兩個整數N、M,分別表示該數列數字的個數和操作的總個數。 第二行包含N個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。 接下來M行每行包含3個整數, ...
  • 最近從百度雲盤上下載了一批視頻,然而這些視頻的文件名都帶有廣告。有潔癖的我看著感覺難受,於是想修改過來。但是一個個的修改文件名又嫌麻煩,聯想到業餘時看過的python,於是用python寫了幾行代碼輕鬆地批量修改了文件名稱。 代碼如下: python學習起來著實有趣,聽說python明年在某個省份要 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...