最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文搞懂 Python 的 abc.ABC基類

 更新時(shí)間:2026年02月04日 09:30:34   作者:Kevin666  
Python里abc.ABC 是“抽象基類”的基類,本文就來介紹一下 Python 的 abc.ABC基類使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

在 Python 里,abc.ABC 是“抽象基類(Abstract Base Class)”的基類。你可以把它理解為:

一個(gè)“專門用來被繼承的類”,它本身不一定能直接用來實(shí)例化,主要作用是 規(guī)定接口、做類型約束

在日常寫 Python 類時(shí),你可能見過這樣的代碼:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def speak(self):
        pass

這里的 ABC 是什么?為什么要這么寫?不寫會(huì)怎樣?這篇文章就來系統(tǒng)講清楚:abc.ABC 到底是干嘛用的、怎么用、什么時(shí)候值得用。

一、abc.ABC是什么?

1. 它來自哪個(gè)模塊?

ABC 定義在標(biāo)準(zhǔn)庫 abc 模塊中:

from abc import ABC

abc 全稱 Abstract Base Classes,即“抽象基類”。
ABC 就是一個(gè)“抽象基類的基類”。

2. 抽象基類(Abstract Base Class)是什么?

抽象基類(簡稱 ABC)是用來 定義接口規(guī)范 的類,它通常具有這些特點(diǎn):

  1. 不打算直接被實(shí)例化(至少設(shè)計(jì)上是這樣);
  2. 定義了一些必須由子類實(shí)現(xiàn)的方法;
  3. 在 Python 中,這些“必須實(shí)現(xiàn)的方法”是通過 @abstractmethod(以及其他類似的裝飾器)標(biāo)記的。

通俗理解:

抽象基類是“接口模板”,子類是“真正干活的實(shí)現(xiàn)”。

二、為什么要用abc.ABC?不用行不行?

先說結(jié)論:不用也“能跑”,但容易亂

1. 不用abc.ABC會(huì)出現(xiàn)的問題

想象你寫了一個(gè)“動(dòng)物”類:

class Animal:
    def speak(self):
        raise NotImplementedError

約定所有子類都要重寫 speak。
問題在于:

  • 可以實(shí)例化 Animal,直到你調(diào)用 speak() 才會(huì)在運(yùn)行時(shí)爆出 NotImplementedError
  • 沒有任何機(jī)制在 類定義階段 檢查“子類到底有沒有實(shí)現(xiàn) speak”。

這意味著:

  • 錯(cuò)誤暴露得晚(運(yùn)行時(shí)才知道);
  • 新人接手代碼時(shí),不知道哪些方法是強(qiáng)制要實(shí)現(xiàn)的,只能靠文檔或注釋。

2. 使用abc.ABC帶來的好處

有了 abc.ABC@abstractmethod

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def speak(self):
        pass

好處立刻顯現(xiàn):

  1. 不能直接實(shí)例化抽象類

    a = Animal()  # TypeError: Can't instantiate abstract class Animal with abstract method speak
    
  2. 子類必須實(shí)現(xiàn)所有抽象方法才能被實(shí)例化

    class Dog(Animal):
        pass
    
    Dog()  # TypeError: Can't instantiate abstract class Dog with abstract method speak
    

    一旦子類漏實(shí)現(xiàn)了 speak,在你實(shí)例化它的時(shí)候就會(huì)立刻報(bào)錯(cuò)。

  3. 抽象方法在 IDE / 文檔里會(huì)有明確標(biāo)記,接口規(guī)范更加清晰。

總結(jié)一下:

不用可以,但用了更安全、更清晰、更工程化。

三、abc.ABC的基本用法

1. 定義抽象基類

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def speak(self):
        """讓動(dòng)物發(fā)出叫聲"""
        pass

    def sleep(self):
        """普通實(shí)例方法,可以有默認(rèn)實(shí)現(xiàn)"""
        print("Zzz...")

這里重點(diǎn):

  • Animal 繼承了 ABC,因此它是一個(gè)抽象基類;
  • speak 上加了 @abstractmethod,代表是抽象方法;
  • sleep 是普通方法,可以給出一個(gè)默認(rèn)實(shí)現(xiàn)。

2. 定義子類并實(shí)現(xiàn)抽象方法

class Dog(Animal):
    def speak(self):
        print("Woof!")

class Cat(Animal):
    def speak(self):
        print("Meow~")

現(xiàn)在:

Dog().speak()  # Woof!
Cat().sleep()  # Zzz...

而如果寫:

class Fish(Animal):
    # 沒有實(shí)現(xiàn) speak
    pass

Fish()  # TypeError: Can't instantiate abstract class Fish with abstract method speak

四、抽象方法可以有方法體嗎?

很多人以為“抽象方法就不能寫代碼”,其實(shí)這是誤解。

在 Python 中,抽象方法完全可以有實(shí)現(xiàn):

from abc import ABC, abstractmethod

class Base(ABC):
    @abstractmethod
    def process(self, data):
        print("Base processing:", data)

子類必須重寫 process,但可以通過 super() 調(diào)用父類的實(shí)現(xiàn):

class Child(Base):
    def process(self, data):
        super().process(data)
        print("Child extra processing:", data)

c = Child()
c.process("hello")
# 輸出:
# Base processing: hello
# Child extra processing: hello

所以:

@abstractmethod 的意義不是“這里不能寫代碼”,而是“子類必須重寫這個(gè)方法”。

五、抽象屬性、類方法、靜態(tài)方法

abc 還提供了更多裝飾器,可以和 @abstractmethod 組合使用。

1. 抽象屬性

from abc import ABC, abstractmethod

class Shape(ABC):
    @property
    @abstractmethod
    def area(self):
        """返回面積"""
        pass

子類必須實(shí)現(xiàn)屬性 area

class Circle(Shape):
    def __init__(self, r):
        self.r = r

    @property
    def area(self):
        return 3.14 * self.r * self.r

如果子類不實(shí)現(xiàn)該屬性,實(shí)例化時(shí)會(huì)報(bào) TypeError。

2. 抽象類方法 / 靜態(tài)方法

from abc import ABC, abstractmethod

class Serializer(ABC):
    @classmethod
    @abstractmethod
    def from_string(cls, s: str):
        """從字符串反序列化"""
        pass

    @staticmethod
    @abstractmethod
    def validate(data):
        """驗(yàn)證數(shù)據(jù)是否合法"""
        pass

子類必須實(shí)現(xiàn) from_stringvalidate

class JsonSerializer(Serializer):
    @classmethod
    def from_string(cls, s: str):
        import json
        return json.loads(s)

    @staticmethod
    def validate(data):
        return isinstance(data, (dict, list))

六、ABC與ABCMeta的關(guān)系

在內(nèi)部,ABC 是用一個(gè)特殊的 metaclass —— ABCMeta 實(shí)現(xiàn)的。

等價(jià)寫法其實(shí)是:

from abc import ABCMeta

class MyABC(metaclass=ABCMeta):
    ...

但日常開發(fā)中,不推薦直接用 ABCMeta,而是:

from abc import ABC

class MyABC(ABC):
    ...

因?yàn)椋?/p>

  • 繼承 ABC 可讀性更好;
  • 很多工具 / IDE 都默認(rèn)識(shí)別這種模式。

簡單記?。?/p>

想定義抽象基類,只需要繼承 ABC,無需直接操作 ABCMeta。

七、abc.ABC在實(shí)際工程中的使用場景

場景 1:定義統(tǒng)一接口,屏蔽實(shí)現(xiàn)細(xì)節(jié)

例如設(shè)計(jì)一個(gè)消息發(fā)送系統(tǒng),希望支持多種渠道(郵箱、短信、釘釘?shù)龋?/p>

from abc import ABC, abstractmethod

class Notifier(ABC):
    @abstractmethod
    def send(self, to, message):
        """發(fā)送消息"""
        pass

各種具體實(shí)現(xiàn):

class EmailNotifier(Notifier):
    def send(self, to, message):
        print(f"Email to {to}: {message}")

class SMSNotifier(Notifier):
    def send(self, to, message):
        print(f"SMS to {to}: {message}")

業(yè)務(wù)代碼只依賴 Notifier 接口:

def notify_user(notifier: Notifier, user, text):
    notifier.send(user.contact, text)

其中 notifier 可以是任意符合接口的實(shí)現(xiàn)類。
日后需要新增一個(gè) DingTalkNotifier,只要繼承 Notifier 并實(shí)現(xiàn) send 即可。

場景 2:插件系統(tǒng)或擴(kuò)展點(diǎn)

例如你寫了一個(gè)框架,想讓別人“插入自己的算法”,就可以用 abc.ABC 規(guī)定一個(gè)基類,讓所有插件作者都按這個(gè)接口實(shí)現(xiàn):

class Plugin(ABC):
    @abstractmethod
    def name(self) -> str:
        pass

    @abstractmethod
    def run(self, data):
        pass

框架側(cè)邏輯:

def run_all_plugins(plugins, data):
    for p in plugins:
        print(f"Running plugin: {p.name()}")
        p.run(data)

插件作者只需要按照約定繼承并實(shí)現(xiàn)方法。
如果漏實(shí)現(xiàn),就會(huì)在實(shí)例化 / 注冊時(shí)直接報(bào)錯(cuò),避免線上才發(fā)現(xiàn)錯(cuò)誤。

場景 3:為類型檢查 / IDE 提供更好支持

抽象基類為 靜態(tài)類型檢查 提供了很好的基礎(chǔ):

def do_something(animal: Animal):
    animal.speak()

類型檢查工具(如 mypy、pyright)能夠根據(jù) Animal 的定義更準(zhǔn)確地判斷類型是否匹配;IDE 也能更好地做自動(dòng)補(bǔ)全。

八、和“鴨子類型”的關(guān)系

Python 一直強(qiáng)調(diào)“鴨子類型”:

像鴨子一樣走路、像鴨子一樣叫,那它就是鴨子。

按照鴨子類型哲學(xué),你甚至不用繼承任何基類,方法名對得上就可以被當(dāng)成“鴨子”。

那抽象基類是不是和鴨子類型相矛盾?其實(shí):

  • 抽象基類強(qiáng)調(diào) 顯式的接口約束
  • 鴨子類型強(qiáng)調(diào) 行為匹配即可。

在大型項(xiàng)目、多人協(xié)作中,顯式約束通常更安全、更易維護(hù);
在小腳本、試驗(yàn)性代碼中,隨意一點(diǎn)無可厚非。

所以:

abc.ABC 不是為了推翻鴨子類型,而是在需要“約束和清晰接口”的地方,給你一把更強(qiáng)的工具。

九、使用abc.ABC的最佳實(shí)踐

  1. 當(dāng)你寫的類“本來就是用來被繼承”的時(shí)候,用 ABC 明確表達(dá)意圖;
  2. 所有需要子類強(qiáng)制實(shí)現(xiàn)的方法,都應(yīng)該加上 @abstractmethod;
  3. 抽象方法可以帶默認(rèn)實(shí)現(xiàn),但請?jiān)?docstring 中說明子類是否需要調(diào)用 super()
  4. 不要濫用:
    • 小型腳本、一次性代碼,沒必要刻意引入 ABC;
    • 對外暴露的庫、框架、長期維護(hù)的項(xiàng)目,強(qiáng)烈建議使用。

十、總結(jié):一句話記住abc.ABC

  • abc.ABC 是 Python 用來定義 抽象基類 的基類;
  • 你通過繼承 ABC + @abstractmethod 來定義“必須由子類實(shí)現(xiàn)”的接口;
  • 它的作用是:讓接口約定更明確,讓錯(cuò)誤更早暴露,讓多人協(xié)作更安全。

如果你在寫庫、寫框架、寫可復(fù)用組件,abc.ABC 是值得熟練掌握的工具。

到此這篇關(guān)于一文搞懂 Python 的 abc.ABC基類的文章就介紹到這了,更多相關(guān)Python abc.ABC 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

博兴县| 苏尼特左旗| 南京市| 原平市| 上栗县| 绥滨县| 玉门市| 英吉沙县| 宜川县| 桃园县| 青浦区| 郴州市| 宁国市| 新营市| 固安县| 南通市| 贵阳市| 通渭县| 景泰县| 开封市| 商城县| 安阳县| 灵山县| 察哈| 栾城县| 通州区| 鸡东县| 土默特左旗| 城步| 景宁| 共和县| 阿尔山市| 仪征市| 永清县| 佛坪县| 佛冈县| 漳州市| 高碑店市| 观塘区| 洪雅县| 龙泉市|