Python 繼承詳解(繼承作用語(yǔ)法)
繼承是面向?qū)ο缶幊蹋∣OP)的一個(gè)重要特性,允許一個(gè)類(子類)從另一個(gè)類(父類)繼承屬性和方法。繼承可以提高代碼的重用性,增強(qiáng)程序的可擴(kuò)展性和可維護(hù)性。
一、繼承的作用
代碼復(fù)用
子類繼承父類的屬性和方法,無(wú)需重復(fù)編寫(xiě)相同代碼。邏輯層次清晰
通過(guò)繼承關(guān)系表達(dá)對(duì)象間的從屬關(guān)系,使代碼更具結(jié)構(gòu)性。增強(qiáng)擴(kuò)展性
子類可以在繼承父類的基礎(chǔ)上擴(kuò)展新的屬性或方法,支持功能擴(kuò)展。多態(tài)性
子類可以重寫(xiě)父類的方法,實(shí)現(xiàn)不同的行為。
二、繼承的語(yǔ)法
在 Python 中,繼承通過(guò)類定義時(shí)括號(hào)中的父類名實(shí)現(xiàn)。
1. 單繼承
子類繼承單個(gè)父類:
class Parent:
def greet(self):
print("Hello from Parent")
class Child(Parent):
pass # 子類繼承了 Parent 的所有屬性和方法
# 使用子類
child = Child()
child.greet() # 輸出: Hello from Parent2. 多繼承
子類繼承多個(gè)父類:
class Parent1:
def greet(self):
print("Hello from Parent1")
class Parent2:
def greet(self):
print("Hello from Parent2")
class Child(Parent1, Parent2):
pass
child = Child()
child.greet() # 輸出: Hello from Parent1 (根據(jù)繼承順序)多繼承會(huì)按照方法解析順序(MRO)決定調(diào)用哪個(gè)父類的方法,可用
Class.mro()或help(Class)查看。
三、子類擴(kuò)展
子類可以添加新的屬性和方法,或者重寫(xiě)父類的方法。
1. 添加新功能
class Parent:
def greet(self):
print("Hello from Parent")
class Child(Parent):
def say_goodbye(self):
print("Goodbye from Child")
child = Child()
child.greet() # 輸出: Hello from Parent
child.say_goodbye() # 輸出: Goodbye from Child2. 重寫(xiě)父類方法
通過(guò)在子類中重新定義方法,覆蓋父類的同名方法。
class Parent:
def greet(self):
print("Hello from Parent")
class Child(Parent):
def greet(self):
print("Hello from Child") # 重寫(xiě)父類方法
child = Child()
child.greet() # 輸出: Hello from Child3. 調(diào)用父類方法
使用 super() 調(diào)用父類方法:
class Parent:
def greet(self):
print("Hello from Parent")
class Child(Parent):
def greet(self):
super().greet() # 調(diào)用父類方法
print("Hello from Child")
child = Child()
child.greet()
# 輸出:
# Hello from Parent
# Hello from Child四、繼承的特殊情況
1. 子類初始化父類
如果父類有 __init__ 方法,子類需要顯式調(diào)用它。
class Parent:
def __init__(self, name):
self.name = name
class Child(Parent):
def __init__(self, name, age):
super().__init__(name) # 調(diào)用父類的初始化方法
self.age = age
child = Child("Alice", 10)
print(child.name) # 輸出: Alice
print(child.age) # 輸出: 102. 方法解析順序(MRO)
多繼承時(shí),Python 按 MRO 順序查找方法。
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
class C(A):
pass
class D(B, C):
pass
print(D.mro())
# 輸出: [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
d = D()
d.show() # 輸出: B五、抽象類與接口
通過(guò)繼承實(shí)現(xiàn)抽象類和接口功能。
1. 抽象類
使用 abc 模塊定義抽象類,要求子類必須實(shí)現(xiàn)特定方法。
from abc import ABC, abstractmethod
class AbstractClass(ABC):
@abstractmethod
def abstract_method(self):
pass
class ConcreteClass(AbstractClass):
def abstract_method(self):
print("Implementation of abstract method")
obj = ConcreteClass()
obj.abstract_method() # 輸出: Implementation of abstract method2. 接口
通過(guò)繼承實(shí)現(xiàn)類似接口的功能,強(qiáng)制子類遵循某些規(guī)則:
class Interface:
def method(self):
raise NotImplementedError("Subclasses must implement this method")
class Implementation(Interface):
def method(self):
print("Method implemented")
obj = Implementation()
obj.method() # 輸出: Method implemented3. ABC類
from abc import ABC, abstractmethod, abstractclassmethod, abstractstaticmethod, abstractproperty
ABC類
這是所有抽象基類的基類。@abstractmethod裝飾器
用于定義抽象方法。子類必須實(shí)現(xiàn)該方法,否則無(wú)法實(shí)例化。@abstractclassmethod、@abstractstaticmethod和@abstractproperty
用于定義抽象的類方法、靜態(tài)方法和屬性。
抽象基類不能直接實(shí)例化,必須由子類實(shí)現(xiàn)所有抽象方法后才能實(shí)例化。所以上述的AbstractClass類不能直接實(shí)例化,必須由ConcreteClass繼承后實(shí)例化。
4. 使用方法
1. 定義抽象基類
from abc import ABC, abstractmethod
# 定義抽象基類
class Shape(ABC):
@abstractmethod
def area(self):
"""計(jì)算面積"""
pass
@abstractmethod
def perimeter(self):
"""計(jì)算周長(zhǎng)"""
pass
# 子類必須實(shí)現(xiàn)所有抽象方法
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
# 實(shí)例化子類
rect = Rectangle(5, 10)
print(rect.area()) # 輸出: 50
print(rect.perimeter()) # 輸出: 30
# 嘗試實(shí)例化抽象類會(huì)報(bào)錯(cuò)
# shape = Shape() # TypeError: Can't instantiate abstract class Shape with abstract methods area, perimeter2. 抽象屬性
使用 @abstractmethod 可以定義抽象屬性。
from abc import *
class Shape(ABC):
@property
@abstractmethod
def name(self):
pass
class Circle(Shape):
@property
def name(self):
return "Circle"
circle = Circle()
print(circle.name) # 輸出: Circle3. 抽象靜態(tài)方法和類方法
可以使用 @abstractstaticmethod 和 @abstractclassmethod。
from abc import *
class Shape(ABC):
@abstractstaticmethod
def description():
pass
@abstractclassmethod
def create(cls):
pass
class Circle(Shape):
@staticmethod
def description():
return "This is a Circle"
@classmethod
def create(cls):
return cls()
circle = Circle()
print(Circle.description()) # 輸出: This is a Circle
circle_instance = Circle.create()4. 檢查子類是否實(shí)現(xiàn)抽象方法
如果子類沒(méi)有實(shí)現(xiàn)抽象方法,嘗試實(shí)例化子類會(huì)拋出 TypeError。
class IncompleteShape(Shape):
pass
# 會(huì)報(bào)錯(cuò),因?yàn)?IncompleteShape 沒(méi)有實(shí)現(xiàn) area 和 perimeter
# shape = IncompleteShape() # TypeError: Can't instantiate abstract class IncompleteShape with abstract methods area, perimeter5. abc 的高級(jí)用法
1. 注冊(cè)虛擬子類
通過(guò) register() 方法,可以將一個(gè)類注冊(cè)為抽象基類的虛擬子類,而無(wú)需繼承抽象基類。
from abc import ABC
class Shape(ABC):
pass
class Polygon:
def sides(self):
return 4
# 將 Polygon 注冊(cè)為 Shape 的虛擬子類
Shape.register(Polygon)
polygon = Polygon()
print(isinstance(polygon, Shape)) # 輸出: True注冊(cè)虛擬子類的行為僅限于 isinstance 和 issubclass 檢查,不會(huì)強(qiáng)制實(shí)現(xiàn)抽象方法。
2. 定義混入類
抽象基類可以作為混入類,提供公共方法供子類繼承,同時(shí)要求子類實(shí)現(xiàn)特定方法。
from abc import ABC, abstractmethod
class JSONSerializable(ABC):
@abstractmethod
def to_json(self):
pass
def save(self, filepath):
with open(filepath, 'w') as f:
f.write(self.to_json())
class User(JSONSerializable):
def __init__(self, name, age):
self.name = name
self.age = age
def to_json(self):
import json
return json.dumps({"name": self.name, "age": self.age})
user = User("Alice", 30)
user.save("user.json")補(bǔ)充
方法解析順序(MRO,Method Resolution Order)
方法解析順序是 Python 中確定在類繼承體系中調(diào)用方法時(shí)的查找順序的規(guī)則。MRO 決定了在多繼承場(chǎng)景下,當(dāng)調(diào)用一個(gè)方法或?qū)傩詴r(shí),Python 應(yīng)該從哪個(gè)類開(kāi)始查找,并以什么順序繼續(xù)查找。
一、MRO 的規(guī)則
深度優(yōu)先、左到右
Python 遵循一種稱為 C3 線性化算法 的規(guī)則,該規(guī)則優(yōu)先考慮深度優(yōu)先,但會(huì)處理多繼承中的沖突,確保類的繼承關(guān)系是線性化的。排除重復(fù)
在繼承樹(shù)中,每個(gè)類只會(huì)被訪問(wèn)一次。保持繼承順序一致
子類的順序會(huì)優(yōu)先于父類,但父類的順序會(huì)根據(jù)定義時(shí)的順序進(jìn)行保留。
二、查看 MRO
在 Python 中,可以使用以下方法查看一個(gè)類的 MRO:
Class.mro()方法:返回一個(gè)類的 MRO 列表。help(Class):顯示類的信息,其中包含 MRO。
示例:
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
class C(A):
pass
class D(B, C):
pass
print(D.mro())
# 輸出: [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
help(D)三、MRO 的應(yīng)用場(chǎng)景
1. 多繼承中方法沖突的處理
多繼承時(shí),如果多個(gè)父類有同名方法,MRO 會(huì)決定調(diào)用哪個(gè)父類的方法。
示例:
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
class C(A):
def show(self):
print("C")
class D(B, C): # 多繼承
pass
d = D()
d.show()
# 輸出: B
# MRO 確定 `D -> B -> C -> A -> object`2. super() 的行為
super() 的調(diào)用遵循 MRO。當(dāng)使用 super() 調(diào)用方法時(shí),會(huì)按照 MRO 順序繼續(xù)查找下一個(gè)類的方法。
示例:
class A:
def greet(self):
print("Hello from A")
class B(A):
def greet(self):
print("Hello from B")
super().greet()
class C(A):
def greet(self):
print("Hello from C")
super().greet()
class D(B, C):
def greet(self):
print("Hello from D")
super().greet()
d = D()
d.greet()
# 輸出:
# Hello from D
# Hello from B
# Hello from C
# Hello from AMRO 確保了 super() 按順序調(diào)用各個(gè)父類的方法。
四、MRO 的規(guī)則解析(C3 線性化算法)
C3 線性化算法是一種合并算法,確保繼承順序具有一致性和邏輯性。
步驟
- 從子類到父類按順序依次列出所有父類。
- 確保子類優(yōu)先于父類。
- 如果一個(gè)類有多個(gè)父類,按定義順序列出父類。
- 保持父類中繼承順序的線性化。
示例:
class A: pass class B(A): pass class C(A): pass class D(B, C): pass print(D.mro()) # 輸出: [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
五、特殊情況
1. 菱形繼承問(wèn)題
菱形繼承是指某個(gè)子類從兩個(gè)父類繼承,而兩個(gè)父類又共同繼承自一個(gè)祖先類的情況。Python 的 MRO 通過(guò) C3 線性化算法解決了菱形繼承問(wèn)題,避免重復(fù)調(diào)用祖先類的方法。
示例:
class A:
def greet(self):
print("Hello from A")
class B(A):
def greet(self):
print("Hello from B")
super().greet()
class C(A):
def greet(self):
print("Hello from C")
super().greet()
class D(B, C):
pass
d = D()
d.greet()
# 輸出:
# Hello from B
# Hello from C
# Hello from A2. 無(wú)法線性化的繼承關(guān)系
如果多繼承中的順序不符合 C3 線性化規(guī)則,Python 會(huì)報(bào)錯(cuò)。
示例:
class X: pass class Y: pass class A(X, Y): pass class B(Y, X): pass class C(A, B): pass # 會(huì)報(bào)錯(cuò),因?yàn)闊o(wú)法確定 MRO 順序
到此這篇關(guān)于Python 繼承詳解(繼承作用語(yǔ)法)的文章就介紹到這了,更多相關(guān)Python 繼承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Python?出現(xiàn)File?“<stdin>“,?line?1非語(yǔ)法錯(cuò)誤的問(wèn)題
這篇文章主要介紹了Python?出現(xiàn)File?“<stdin>“,?line?1非語(yǔ)法錯(cuò)誤的解決辦法,本文給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03
Python中函數(shù)的創(chuàng)建及調(diào)用
這篇文章主要介紹了Python中函數(shù)的創(chuàng)建及調(diào)用,創(chuàng)建函數(shù)也稱為定義一個(gè)函數(shù),可以理解為創(chuàng)建一個(gè)具有某種用途的工具。調(diào)用函數(shù)也就是執(zhí)行函數(shù)。如果把創(chuàng)建的函數(shù)理解為創(chuàng)建一個(gè)具體有某種用途的工具,那么調(diào)用函數(shù)就相當(dāng)于使用該工具2022-06-06
MacOS使用pyenv和brew優(yōu)雅管理Python多版本環(huán)境
本文采用「pyenv?+?Homebrew」方案,為?MacOS?搭建干凈、隔離的?Python?多版本環(huán)境,徹底避免污染系統(tǒng)自帶?Python,完美適配不同項(xiàng)目版本需求,有需要的小伙伴可以參考下2026-03-03
如何使用Python 抓取和優(yōu)化所有網(wǎng)站圖像
我發(fā)布了一個(gè)通過(guò)FTP自動(dòng)優(yōu)化新圖像的教程。這次我們將抓取整個(gè)網(wǎng)站,并在本地優(yōu)化我們遇到的圖像,按URL組織,怎么來(lái)操作呢,下面跟隨小編一起學(xué)習(xí)使用Python 抓取和優(yōu)化所有網(wǎng)站圖像的方法,感興趣的朋友一起看看吧2023-02-02
Python調(diào)用ChatGPT的API實(shí)現(xiàn)文章生成
最近ChatGPT大火,在3.5版本后開(kāi)放了接口API,所以很多人開(kāi)始進(jìn)行實(shí)操,這里我就用python來(lái)為大家實(shí)現(xiàn)一下,如何調(diào)用API并提問(wèn)返回文章的說(shuō)明2023-03-03
Python matplotlib修改默認(rèn)字體的操作
這篇文章主要介紹了Python matplotlib修改默認(rèn)字體的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
利用Python實(shí)現(xiàn)Markdown與Excel互轉(zhuǎn)
本文介紹了如何使用Python實(shí)現(xiàn)Excel和Markdown之間的轉(zhuǎn)換,重點(diǎn)包括基礎(chǔ)轉(zhuǎn)換、高級(jí)設(shè)置調(diào)整、從復(fù)雜文檔中提取表格并轉(zhuǎn)換為Excel,轉(zhuǎn)換原因包括提升文檔兼容性、優(yōu)化展示體驗(yàn)、適配版本控制、簡(jiǎn)化數(shù)據(jù)分析和工作流整合,文中提供了具體代碼示例,幫助讀者輕松實(shí)現(xiàn)轉(zhuǎn)換2026-04-04

