Logo

新人日誌

首頁關於我部落格

新人日誌

Logo

網站會不定期發佈技術筆記、職場心得相關的內容,歡迎關注本站!

網站
首頁關於我部落格
部落格
分類系列文

© 新人日誌. All rights reserved. 2020-present.

理解 Python 的方法解析順序 (MRO):Django 多重繼承的最佳實踐

最後更新:2024年12月26日Python

本文為圖片轉 WebP 功能模組化系列文,第 9 篇:

  1. 如何設計 Django 的通用工具,並選擇適合的存放位置
  2. 從零開始:如何實現圖片轉 WebP 並上傳到 S3 的功能
  3. 使用基類模型(class model)優化代碼:從零到掌握 DRY 原則
  4. Django 抽象模型:理解 class Meta: abstract = True
  5. 為什麼要分離圖片處理邏輯?Django 最佳實踐指南
  6. Django 信號處理:如何在保存前自動處理圖片
  7. Django 信號處理的最佳實踐:如何選擇合適的位置
  8. 將圖片處理移至信號:模型設計的最佳實踐
  9. 理解 Python 的方法解析順序 (MRO):Django 多重繼承的最佳實踐 👈 所在位置

建議閱讀本文前,先閱讀完 圖片轉 WebP 系列文

在 Django 中,模型經常需要通過多重繼承來添加附加功能(如圖片處理、數據校驗等)。

這時,類的繼承順序至關重要,因為 Python 使用方法解析順序 (MRO) 決定哪個方法會被調用。

本文將帶你了解 MRO 的工作原理,以及如何正確設計繼承結構,確保功能正常運行。


MRO 的運作原理

MRO(Method Resolution Order)是 Python 用來決定哪個類的方法應該被調用的一套規則。

當對象調用方法時,Python 按照類的繼承順序從左到右查找方法,並執行第一個找到的同名方法。

基本解析規則

當你調用一個方法(如 save)時,Python 按以下順序查找:

  1. 先在當前類中查找方法。
  2. 如果找不到,依次檢查繼承列表中從左到右的父類。
  3. 按照這個順序,第一個找到的方法將被執行,其它同名方法被忽略。

使用 MRO 的範例

定義兩個類和一個子類

class Mixin:
    def save(self, *args, **kwargs):
        print("Mixin save called")
        super().save(*args, **kwargs)

class Model:
    def save(self, *args, **kwargs):
        print("Model save called")

class Profile(Mixin, Model):
    pass

調用方法

profile = Profile()
profile.save()

輸出結果

Mixin save called
Model save called

解析順序

  1. Python 首先檢查 Profile 類,沒有找到 save 方法。
  2. 按照 MRO,檢查 Mixin 類,找到並執行其 save 方法。
  3. 如果 Mixin.save 調用了 super(), 會接著執行 Model.save 方法。

MRO 在多重繼承中的影響

在多重繼承中,繼承順序的設置對於方法的調用至關重要。

正確的順序

將附加功能的 Mixin 類放在前面,基類(如 models.Model)放在最後:

class Profile(WebPImageModelMixin, models.Model):
    pass

原因:

  • Mixin 的方法(如 save)將優先於 models.Model 的默認方法。
  • 保證 Mixin 的功能能正確覆蓋或擴展基類的行為。

錯誤的順序

如果基類放在前面,Mixin 的方法可能不會被執行:

class Profile(models.Model, WebPImageModelMixin):
    pass

問題:

  • models.Model.save 可能覆蓋 WebPImageModelMixin.save,導致圖片處理邏輯無法正確執行。

如何確認 MRO?

Python 提供了 ClassName.mro() 方法來檢查 MRO。

例如:

print(Profile.mro())

正確順序時(Mixin 在前)

[<class '__main__.Profile'>, <class '__main__.WebPImageModelMixin'>, <class 'django.db.models.Model'>, ...]

錯誤順序時(Mixin 在後)

[<class '__main__.Profile'>, <class 'django.db.models.Model'>, <class '__main__.WebPImageModelMixin'>, ...]

最佳實踐

  1. 將 Mixin 放在左側,基類放在右側: class Profile(WebPImageModelMixin, models.Model):
  2. 檢查 MRO: 使用 ClassName.mro() 確保繼承順序正確。
  3. 設計覆蓋功能的 Mixin: Mixin 的方法應調用 super() 以確保基類的功能仍然被執行。

結論

  • Python 的方法解析順序 (MRO) 决定了多重繼承中的方法調用順序。
  • 正確的繼承順序至關重要,推薦將功能性的 Mixin 放在基類之前。
  • 使用 ClassName.mro() 確保方法解析符合預期,避免潛在的功能缺失。

遵循這些最佳實踐,可以讓你的代碼更加靈活、易於維護,並充分利用 Django 和 Python 的強大功能! 🎯

目前還沒有留言,成為第一個留言的人吧!

發表留言

留言將在審核後顯示。

Python

目錄

  • MRO 的運作原理
  • 基本解析規則
  • 使用 MRO 的範例
  • MRO 在多重繼承中的影響
  • 正確的順序
  • 錯誤的順序
  • 如何確認 MRO?
  • 正確順序時(Mixin 在前)
  • 錯誤順序時(Mixin 在後)
  • 最佳實踐
  • 結論