全網最適合入門的面向對象編程教程:44 Python內置函數與魔法方法-重寫內置類型的魔法方法

来源:https://www.cnblogs.com/FreakEmbedded/p/18393798
-Advertisement-
Play Games

在 Python 中,內置類型的行為是通過一組特殊的“魔法方法”來實現的,這些魔法方法以雙下劃線開頭和結尾,比如 init 和 str,你可以通過重寫這些魔法方法來定製或擴展內置類型的行為。 ...


全網最適合入門的面向對象編程教程:44 Python 內置函數與魔法方法-重寫內置類型的魔法方法

image

摘要:

在 Python 中,內置類型的行為是通過一組特殊的“魔法方法”來實現的,這些魔法方法以雙下劃線開頭和結尾,比如 init 和 str,你可以通過重寫這些魔法方法來定製或擴展內置類型的行為。

原文鏈接:

FreakStudio的博客

往期推薦:

學嵌入式的你,還不會面向對象??!

全網最適合入門的面向對象編程教程:00 面向對象設計方法導論

全網最適合入門的面向對象編程教程:01 面向對象編程的基本概念

全網最適合入門的面向對象編程教程:02 類和對象的 Python 實現-使用 Python 創建類

全網最適合入門的面向對象編程教程:03 類和對象的 Python 實現-為自定義類添加屬性

全網最適合入門的面向對象編程教程:04 類和對象的Python實現-為自定義類添加方法

全網最適合入門的面向對象編程教程:05 類和對象的Python實現-PyCharm代碼標簽

全網最適合入門的面向對象編程教程:06 類和對象的Python實現-自定義類的數據封裝

全網最適合入門的面向對象編程教程:07 類和對象的Python實現-類型註解

全網最適合入門的面向對象編程教程:08 類和對象的Python實現-@property裝飾器

全網最適合入門的面向對象編程教程:09 類和對象的Python實現-類之間的關係

全網最適合入門的面向對象編程教程:10 類和對象的Python實現-類的繼承和里氏替換原則

全網最適合入門的面向對象編程教程:11 類和對象的Python實現-子類調用父類方法

全網最適合入門的面向對象編程教程:12 類和對象的Python實現-Python使用logging模塊輸出程式運行日誌

全網最適合入門的面向對象編程教程:13 類和對象的Python實現-可視化閱讀代碼神器Sourcetrail的安裝使用

全網最適合入門的面向對象編程教程:全網最適合入門的面向對象編程教程:14 類和對象的Python實現-類的靜態方法和類方法

全網最適合入門的面向對象編程教程:15 類和對象的 Python 實現-__slots__魔法方法

全網最適合入門的面向對象編程教程:16 類和對象的Python實現-多態、方法重寫與開閉原則

全網最適合入門的面向對象編程教程:17 類和對象的Python實現-鴨子類型與“file-like object“

全網最適合入門的面向對象編程教程:18 類和對象的Python實現-多重繼承與PyQtGraph串口數據繪製曲線圖

全網最適合入門的面向對象編程教程:19 類和對象的 Python 實現-使用 PyCharm 自動生成文件註釋和函數註釋

全網最適合入門的面向對象編程教程:20 類和對象的Python實現-組合關係的實現與CSV文件保存

全網最適合入門的面向對象編程教程:21 類和對象的Python實現-多文件的組織:模塊module和包package

全網最適合入門的面向對象編程教程:22 類和對象的Python實現-異常和語法錯誤

全網最適合入門的面向對象編程教程:23 類和對象的Python實現-拋出異常

全網最適合入門的面向對象編程教程:24 類和對象的Python實現-異常的捕獲與處理

全網最適合入門的面向對象編程教程:25 類和對象的Python實現-Python判斷輸入數據類型

全網最適合入門的面向對象編程教程:26 類和對象的Python實現-上下文管理器和with語句

全網最適合入門的面向對象編程教程:27 類和對象的Python實現-Python中異常層級與自定義異常類的實現

全網最適合入門的面向對象編程教程:28 類和對象的Python實現-Python編程原則、哲學和規範大彙總

全網最適合入門的面向對象編程教程:29 類和對象的Python實現-斷言與防禦性編程和help函數的使用

全網最適合入門的面向對象編程教程:30 Python的內置數據類型-object根類

全網最適合入門的面向對象編程教程:31 Python的內置數據類型-對象Object和類型Type

全網最適合入門的面向對象編程教程:32 Python的內置數據類型-類Class和實例Instance

全網最適合入門的面向對象編程教程:33 Python的內置數據類型-對象Object和類型Type的關係

全網最適合入門的面向對象編程教程:34 Python的內置數據類型-Python常用複合數據類型:元組和命名元組

全網最適合入門的面向對象編程教程:35 Python的內置數據類型-文檔字元串和__doc__屬性

全網最適合入門的面向對象編程教程:36 Python的內置數據類型-字典

全網最適合入門的面向對象編程教程:37 Python常用複合數據類型-列表和列表推導式

全網最適合入門的面向對象編程教程:38 Python常用複合數據類型-使用列表實現堆棧、隊列和雙端隊列

全網最適合入門的面向對象編程教程:39 Python常用複合數據類型-集合

全網最適合入門的面向對象編程教程:40 Python常用複合數據類型-枚舉和enum模塊的使用

全網最適合入門的面向對象編程教程:41 Python常用複合數據類型-隊列(FIFO、LIFO、優先順序隊列、雙端隊列和環形隊列)

全網最適合入門的面向對象編程教程:42 Python常用複合數據類型-collections容器數據類型

全網最適合入門的面向對象編程教程:43 Python常用複合數據類型-擴展內置數據類型

更多精彩內容可看:

給你的 Python 加加速:一文速通 Python 並行計算

一文搞懂 CM3 單片機調試原理

肝了半個月,嵌入式技術棧大彙總出爐

電子電腦類比賽的“武林秘籍”

一個MicroPython的開源項目集錦:awesome-micropython,包含各個方面的Micropython工具庫

Avnet ZUBoard 1CG開發板—深度學習新選擇

SenseCraft 部署模型到Grove Vision AI V2圖像處理模塊

文檔和代碼獲取:

可訪問如下鏈接進行對文檔下載:

https://github.com/leezisheng/Doc

image

本文檔主要介紹如何使用 Python 進行面向對象編程,需要讀者對 Python 語法和單片機開發具有基本瞭解。相比其他講解 Python 面向對象編程的博客或書籍而言,本文檔更加詳細、側重於嵌入式上位機應用,以上位機和下位機的常見串口數據收發、數據處理、動態圖繪製等為應用實例,同時使用 Sourcetrail 代碼軟體對代碼進行可視化閱讀便於讀者理解。

相關示例代碼獲取鏈接如下:https://github.com/leezisheng/Python-OOP-Demo

正文

Python 內置函數與魔法方法

Python 中有許多函數可以針對特定類型的對象執行某些任務或計算結果,這些函數不需要是某些底層類的方法。它們通常是抽象出來的一些常用計算,可以應用於多種類型的類。這些函數統稱內置函數,我們往往使用內置函數調用對象的魔法方法,所謂魔法方法(Magic Method)是 python 內置方法,以兩個下劃線開頭、兩個下劃線結尾,它不需要主動調用,存在的目的是為了給 python 的解釋器進行調用。常見內置函數有以下這些:

image

最簡單的例子就是 len()內置函數,它可以數出某種容器對象中的項目數,例如字典或列表。實際上,列表對象並沒有 len 長度屬性,你可能不相信,那就讓我們查看一下列表 List 的屬性值。輸入如下代碼:

print(list.__dict__)

我們來看一下輸出:

{'__new__': <built-in method __new__ of type object at 0x00007FF9D4D5B6D0>,
 '__repr__': <slot wrapper '__repr__' of 'list' objects>, '__hash__': None, 
'__getattribute__': <slot wrapper '__getattribute__' of 'list' objects>, 
'__lt__': <slot wrapper '__lt__' of 'list' objects>, '__le__': <slot wrapper 
'__le__' of 'list' objects>, '__eq__': <slot wrapper '__eq__' of 'list' objects>, 
'__ne__': <slot wrapper '__ne__' of 'list' objects>, 
'__gt__': <slot wrapper '__gt__' of 'list' objects>, '__ge__': <slot wrapper '__ge__' of 'list' objects>, '__iter__': <slot wrapper '__iter__' of 'list' objects>, 
'__init__': <slot wrapper '__init__' of 'list' objects>, '__len__': <slot wrapper '__len__' of 'list' objects>,
 '__getitem__': <method '__getitem__' of 'list' objects>, '__setitem__': <slot wrapper '__setitem__' of 'list' objects>,
 '__delitem__': <slot wrapper '__delitem__' of 'list' objects>, '__add__': <slot wrapper '__add__' of 'list' objects>,
 '__mul__': <slot wrapper '__mul__' of 'list' objects>, '__rmul__': <slot wrapper '__rmul__' of 'list' objects>, 
'__contains__': <slot wrapper '__contains__' of 'list' objects>, '__iadd__': <slot wrapper '__iadd__' of 'list' objects>, '__imul__': <slot wrapper '__imul__' of 'list' objects>,
 '__reversed__': <method '__reversed__' of 'list' objects>, '__sizeof__': <method '__sizeof__' of 'list' objects>,
 'clear': <method 'clear' of 'list' objects>, 'copy': <method 'copy' of 'list' objects>, 'append': <method 'append' of 'list' objects>,
 'insert': <method 'insert' of 'list' objects>, 'extend': <method 'extend' of 'list' objects>, 'pop': <method 'pop' of 'list' objects>,
'remove': <method 'remove' of 'list' objects>, 'index': <method 'index' of 'list' objects>, 'count': <method 'count' of 'list' objects>,
 'reverse': <method 'reverse' of 'list' objects>, 'sort': <method 'sort' of 'list' objects>, '__class_getitem__': <method '__class_getitem__' of 'list' objects>, 
'__doc__': 'Built-in mutable sequence.\n\nIf no argument is given, the constructor creates a new empty list.\nThe argument m

我丟,還真沒有,這是怎麼回事?那為什麼我們用 len()函數居然能得到列表的長度?從理論上來說,列表是有長度屬性的。len()應用到的大部分對象都有一個被稱為 len()的方法,其返回同樣的值。因此 len(list)就是調用 list.len()(len()為內置函數、len 為魔法方法)

那麼為什麼不用__len__方法而要用 len()函數?

很明顯 len 是一個特殊的雙下畫線方法,這意味著我們不應該直接調用它,主要的原因是效率,利用內置函數調用魔法方法不僅提供額外的服務,而且解釋器做了優化,會比調用方法更快。通過調用 len()函數,我們可以直接訪問 Python 可變長度容器的底層 C 語言中 PyVarObject 結構體的 ob_size 欄位,該欄位保存著容器中的項數。 len(my_object)直接讀取 ob_size 欄位的值,這比調用 len 方法快很多。

另一個原因是可維護性。Python 開發者可能會在未來修改 len()來計算沒有 len 方法的對象的長度,例如,通過計數迭代器返回的項目。那麼他們只需要修改一個函數而不是所有的 len 方法。

除了__len__的例子外,最常見的例子就是要拿到一個列表的某個元素,可以使用對應的引索進行取值,比如 list[key],這背後利用的是__getitem__方法,為了拿到 my_list[key]的值,解釋器實際上會調用 my_list.getitem(key)。

那麼如何得到 Python 內置數據類型的這些特殊方法呢?非常簡單,只需要應用 dir([object])函數即可,dir()函數可以返回對象的屬性、方法列表。以 List 列表類為例,我們只需要輸入以下語句即可:

print(dir(list))

輸出如下:

['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', 
'__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', 
'__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', 
'__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', 
'__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', 
'__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 
'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

此外,如果想要知道如何使用這些方法,可以用 help 函數:

print(help(list.__le__))

輸出如下:

image

實際上,python 中常見的魔法方法大致可分為以下幾類:構造與初始化、類的表示、操作符、訪問控制、容器類操作、可調用對象、序列化操作等。我們在下圖中對常用魔法方法進行了總結:

image

image

image

image

image

image

image

image

image

重寫內置類型的魔法方法

重寫是子類對父類的允許訪問的方法的實現過程進行重新編寫, 返回值和形參都不能改變。重寫的好處在於子類可以根據需要,定義特定於自己的行為。

這裡以魔法方法中的__repr__方法和__ str__方法講解如何重寫內置類型的魔法方法。

所謂 repr 是 Python 類中的一個特殊方法,由 object 對象提供,由於所有類都是 object 類的子類,所以都會繼承該方。它是一個”自我描述“的方法,此方法通常實現這樣的功能:當直接列印類的實例化對象時,系統將會輸出對象的自我描述信息,用來告訴外界對象具有的狀態信息。通常情況下,直接輸出某個實例化對象,本意往往是想瞭解該對象的基本信息,例如該對象有哪些屬性,它們的值各是多少等等。但是由於 object 提供的這個 repr 方法總是返回一個對象,(類名 + obejct at + 記憶體地址),這個值並不能真正實現自我描述的功能。因此,如果你想在自定義類中實現“自我描述” 的功能,那麼必須重寫 repr 方法。

與 repr 類似的是__ str__方法,repr 和 str 這兩個方法都是用於顯示的,str 是面向用戶的,而 repr 面向程式員:

  • 列印操作會首先嘗試 str 和 str 內置函數(print 運行的內部等價形式),它通常應該返回一個友好的顯示;
  • repr 用於所有其他的環境中:用於交互模式下提示回應以及 repr 函數,如果沒有使用 str,會使用 print 和 str。它通常應該返回一個編碼字元串,可以用來重新創建對象,或者給開發者詳細的顯示。

同時,我們也可以對算數操作符進行重寫,在上述列表實現集合的例子中,如下代碼就是對算數操作符進行重寫:

_# 運算符&重載,求交集_
    def __and__(self, other):
        return self.intersect(other)
    _# 運算符|重載,求合集_
    def __or__(self, other):
        return self.union(other)
    _# 當直接列印類的實例化對象時,系統將會輸出對象的自我描述信息_
    def __repr__(self):
        return 'Set:' + repr(self.data)

再列舉一個有趣的例子,對算數操作符方法重寫進行說明,以下代碼創建一個特殊的整數,每當將兩個這種整數相加時都會返回 0:

class SillyInt(int):
    _# 重寫__add__方法_
    def __add__(self, num):
        return 0
    
a = SillyInt(1)
b = SillyInt(2)

print(a+b)

如下為運行結果,儘管這個例子沒有什麼實際應用的例子,但還是能很好的講述如何對算數操作符方法進行重寫:

image

重寫後的__add__方法可以添加到任何我們自己寫的類中,如果我對這個類的實例使用 + 操作符,將會調用__add__。例如,字元串、元組以及列表的連接就是這麼實現的。所有的特殊方法都是這樣的。如果想要對自定義的對象使用 x in myobj 語法,可以實現__contains__方法。如果想要用 myobj[i] = value 語法,只需要提供__setitem__方法。如果想用 something = myobj[i],需要實現__getitem__。

image


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

-Advertisement-
Play Games
更多相關文章
  • UML類圖 UML類圖 是一種靜態的結構圖,描述了系統的類的集合,類的屬性和類之間的關係,可以簡化了人們對系統的理解。UML類圖 是系統分析和設計階段的重要產物,是系統編碼和測試的重要模型。 圖示 類 解析 圓角矩形框,它就代表一個類(Class) 類圖分為三層: 第一層顯示類的名稱,如果是抽象類, ...
  • @目錄1.工作空間目錄1.1 package.xml2.啟動節點的方式2.1 一次啟動一個2.2 一次啟動多個3.ROS常用命令3.1 增3.2 查3.3 執行3.3.1 載入環境變數3.3.2 運行節點3.4 查看計算圖4.創建功能包4.1 選擇工作目錄4.2 創建功能包目錄4.3 建立功能包 1 ...
  • @目錄1.rosnode1.1 rosnode ping1.1.1 測試所有節點的連接狀態1.1.2 測試到某個節點的連接狀態1.2 rosnode list1.3 rosnode info1.4 rosnode machine1.4.1 列出所有設備1.4.2 查看指定設備上的運行節點1.5 ro ...
  • @目錄1.節點初始化2.話題通信2.1 創建發佈者對象2.2 消息發佈2.3 創建訂閱者對象3.服務通信3.1 創建服務對象3.2 創建客戶對象3.3 客戶發送請求3.4 客戶對象等待服務4. 迴旋函數4.1 spin4.2 spinOnce5.時間5.1 時刻5.1.1 獲取當前時刻5.1.2 設 ...
  • 日誌處理logging 一、日誌輸出 日誌預設的輸出等級為:waring級別及以上的等級 修改日誌的預設輸出等級通過logging.basicConfig(level='INFO') 記錄日誌列印時間:logging.basicConfig(format=console_fmt) console_f ...
  • 一、 六大設計原則 1. 單一職責原則:應該有且僅有一個原因引起類的變更 2. 里氏替換原則:子類可替換父類。 a) 子類必須完全實現父類的方法 b) 子類可以有自己的個性 c) 子類實現父類方法時,入參可放大 d) 子類實現父類方法時,輸出參數可縮小 3. 依賴倒置原則:高層模塊不應該依賴底層模塊 ...
  • 事件匯流排(在有些框架中也稱時間聚合器,如Prism的EventAggregater)是訂閱-發佈模式的一種實現,類似觀察者模式,相對於觀察者模式,事件匯流排更靈活,它是一種集中處理事件的模式,允許不同組件之間通信,降低耦合度。 事件匯流排的三要素:事件源(事件的定義)、發佈事件(觸發事件)、訂閱事件(事 ...
  • IT統一運維平臺案例統一運維平臺的架構圖,劃分為三個主要部分:統一運維門戶、報告與決策中心、運維服務調度中心。以下是對每個部分的解析:1. 統一運維門戶這是用戶的統一入口,提供了一系列運維相關的服務和功能,包括:綜合信息發佈:發佈運維相關的信息,如公告、通知等。 自助服務台:用戶可以通過自助服務台提 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...