Python 屬性查找:深入理解__getattribute__與__getattr__

目錄

一、__getattribute__方法詳解

1.1 基本概念

1.2 示例分析

1.3 注意事項

二、__getattr__方法詳解

2.1 基本概念

2.2 示例分析

2.3 注意事項

三、__getattribute__與__getattr__的區別對比

3.1 調用時機

3.2 應用場景

3.3 性能影響

四、屬性查找順序


屬性查找是一個基礎而又關鍵的操作,當我們使用點號(.)來訪問對象的屬性時,比如obj.attr,Python 會在對象及其所屬類的層次結構中進行搜索,以找到對應的屬性值。在這個過程中,__getattribute__和__getattr__這兩個特殊方法起著至關重要的作用。理解它們的工作機制和區別,對于編寫高效、健壯的 Python 代碼至關重要。本文將深入探討這兩個方法,幫助大家掌握它們的用法。

一、__getattribute__方法詳解


1.1 基本概念

__getattribute__是 Python 中的一個特殊方法,屬于新式類(在 Python 2.2 及以上版本中,所有類默認都是新式類)。

當我們嘗試訪問對象的任何屬性時,無論該屬性是否存在,Python 都會首先調用對象的__getattribute__方法。這個方法的定義如下:

def __getattribute__(self, name):pass

其中,self是對象自身的引用,name是要訪問的屬性名稱,它是一個字符串。例如,當執行obj.attr時,name的值就是'attr'。

1.2 示例分析

class MyClass:def __init__(self):self.attribute = "Hello, World!"def __getattribute__(self, name):print(f"正在訪問屬性: {name}")return super().__getattribute__(name)obj = MyClass()
print(obj.attribute)

在上述代碼中,我們定義了一個MyClass類,并在其中重寫了__getattribute__方法。當創建obj實例并訪問其attribute屬性時,__getattribute__方法會首先被調用。它打印出正在訪問的屬性名稱,然后通過super().__getattribute__(name)調用父類(即object類)的__getattribute__方法來獲取實際的屬性值。這樣做是為了避免在__getattribute__方法內部出現無限遞歸調用。如果我們在__getattribute__方法中直接使用self.name來獲取屬性值,會再次觸發__getattribute__方法,從而導致遞歸錯誤。

1.3 注意事項

在重寫__getattribute__方法時,一定要注意避免遞歸錯誤。如前面提到的,不要在方法內部使用self.attr這種方式來獲取屬性值,而應該使用super().__getattribute__(attr)。另外,__getattribute__方法無論屬性是否存在都會被調用,這意味著即使訪問一個不存在的屬性,也會進入這個方法。如果在__getattribute__方法中沒有找到對應的屬性,并且沒有拋出AttributeError異常,那么__getattr__方法將不會被調用。

二、__getattr__方法詳解


2.1 基本概念

__getattr__同樣是 Python 中的特殊方法。

與__getattribute__不同,__getattr__只有在常規的屬性查找(在對象的__dict__和類的__dict__及其父類的__dict__中查找)失敗,并且對象所屬的類定義了__getattr__方法時才會被調用。它的定義如下:

def __getattr__(self, name):pass

self和name的含義與__getattribute__方法中的相同。當 Python 在對象及其類的層次結構中找不到指定的屬性時,就會調用__getattr__方法,嘗試通過這個方法來獲取屬性值或者提供默認行為。

2.2 示例分析

class MyClass:def __init__(self):self.attribute = "Hello, World!"def __getattr__(self, name):if name == "nonexistent_attribute":return "這個屬性不存在,但我可以返回一個默認值"raise AttributeError(f"'MyClass' object has no attribute '{name}'")obj = MyClass()
print(obj.attribute)
print(obj.nonexistent_attribute)

在這個例子中,我們定義了MyClass類并實現了__getattr__方法。當訪問obj的attribute屬性時,由于該屬性存在于對象的__dict__中,所以__getattr__方法不會被調用,直接返回屬性值。而當訪問nonexistent_attribute屬性時,常規屬性查找失敗,Python 會調用__getattr__方法。在__getattr__方法中,我們檢查屬性名稱,如果是nonexistent_attribute,則返回一個默認值;否則,拋出AttributeError異常,表明對象確實沒有該屬性。

2.3 注意事項

__getattr__方法主要用于處理不存在的屬性訪問。在實現這個方法時,要確保對于確實不存在的屬性拋出AttributeError異常,這樣可以保持 Python 屬性查找機制的一致性,也便于其他開發者理解和調試代碼。另外,__getattr__方法只有在常規屬性查找失敗時才會被調用,這與__getattribute__方法的調用時機有明顯區別。

三、__getattribute__與__getattr__的區別對比


3.1 調用時機

  • __getattribute__:在每次訪問對象屬性時都會被調用,無論該屬性是否存在于對象及其類的層次結構中。
  • __getattr__:只有在常規屬性查找(在對象的__dict__和類的__dict__及其父類的__dict__中查找)失敗后才會被調用。可以說__getattr__是屬性查找的 “后備方案”。

3.2 應用場景

  • __getattribute__:適用于需要對所有屬性訪問進行統一攔截和處理的場景,比如實現屬性訪問日志記錄、權限檢查等。例如,我們可以在__getattribute__方法中記錄每次屬性訪問的時間、訪問者信息等。
  • __getattr__:主要用于為不存在的屬性提供默認行為,例如實現懶加載(只有在真正訪問某個屬性時才去加載相關資源)、代理訪問(通過一個代理對象來訪問其他對象的屬性)等。比如,在一個數據庫連接對象中,可以使用__getattr__方法,當訪問某個表名屬性時,如果該表對象尚未加載,就自動進行加載操作。

3.3 性能影響

由于__getattribute__方法在每次屬性訪問時都會被調用,所以它對性能的影響相對較大。尤其是在一個對象有大量屬性訪問操作的情況下,如果在__getattribute__方法中進行了復雜的邏輯處理,可能會導致性能瓶頸。而__getattr__方法只有在屬性查找失敗時才會被調用,因此在大多數情況下,它對性能的影響較小。所以,在選擇使用哪個方法時,除了考慮功能需求,也要考慮性能因素。例如,在一個性能要求較高且大部分屬性都存在的場景中,應盡量避免在__getattribute__方法中添加過多復雜邏輯;而在一個屬性訪問不確定性較大,且需要為不存在的屬性提供默認行為的場景中,__getattr__方法是更好的選擇。

四、屬性查找順序


當我們執行obj.attr這樣的屬性訪問操作時,Python 的屬性查找順序如下:

  1. 調用__getattribute__方法:無論屬性是否存在,首先調用對象的__getattribute__方法。如果在這個方法中通過super().__getattribute__(name)成功獲取到屬性值,則返回該值,查找過程結束。如果在__getattribute__方法中拋出了AttributeError異常(例如,屬性確實不存在或者在__getattribute__方法內部邏輯判斷該屬性不應該被訪問),則進入下一步。
  2. 檢查數據描述符:如果屬性是類中的數據描述符(即實現了__get__、__set__和__delete__方法的描述符),則調用數據描述符的__get__方法獲取屬性值,查找過程結束。
  3. 查找實例屬性:在對象的__dict__中查找屬性。如果找到,則返回該屬性值,查找過程結束。
  4. 檢查類屬性和非數據描述符:在類的__dict__及其父類的__dict__中查找屬性。如果找到的屬性是一個非數據描述符(只實現了__get__方法的描述符),則調用其__get__方法獲取屬性值;如果找到的不是描述符屬性,則直接返回該屬性值,查找過程結束。
  5. 調用__getattr__方法:如果上述所有步驟都沒有找到屬性,并且對象所屬的類定義了__getattr__方法,則調用__getattr__方法。如果__getattr__方法返回了一個值,則返回該值;如果__getattr__方法拋出了AttributeError異常,則最終拋出該異常,表示屬性不存在。

為了更清晰地展示這個過程,我們可以用表格形式總結如下:

步驟

操作

說明

1

調用__getattribute__

首先執行,無論屬性是否存在

2

檢查數據描述符

若屬性是數據描述符,調用其__get__方法

3

查找實例屬性

在對象的__dict__中查找

4

檢查類屬性和非數據描述符

在類及其父類的__dict__中查找,區分非數據描述符和普通屬性

5

調用__getattr__

若上述步驟均未找到,且類定義了該方法,則調用

理解這個屬性查找順序,對于深入掌握__getattribute__和__getattr__的工作原理以及它們在屬性查找過程中的作用至關重要。

通過本文的介紹,相信大家對 Python 中的__getattribute__和__getattr__方法有了更深入的理解。它們雖然都是與屬性查找相關的特殊方法,但在調用時機、應用場景和對性能的影響等方面存在明顯區別。在實際編程中,我們應根據具體需求合理選擇使用這兩個方法,以編寫出高效、優雅的 Python 代碼。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/86202.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/86202.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/86202.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

打表法從原理到實戰詳解

打表法結合經典案例從原理到實戰詳解 一、打表法基本信息1.1 打表法定義1.2 打表法適用場景1.3 打表法的優缺點 二、打表法經典案例解析2.1 快速計算斐波那契數列2.1.1 問題描述2.1.2 打表思路2.1.3 Java代碼實現2.1.4 復雜度分析 2.2 快速判斷質數(埃氏篩法結合打表…

(LeetCode 面試經典 150 題 )121. 買賣股票的最佳時機 (遍歷)

題目&#xff1a;121. 買賣股票的最佳時機 思路&#xff1a;遍歷&#xff0c;維護已遍歷過的元素中的最小值&#xff0c;時間復雜度0(n)。 C版本&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {int mnprices[0];int mx0;for(int i1;i&…

(洛谷)P4447 [AHOI2018初中組] 分組

題目描述 小可可的學校信息組總共有 n 個隊員&#xff0c;每個人都有一個實力值 ai?。現在&#xff0c;一年一度的編程大賽就要到了&#xff0c;小可可的學校獲得了若干個參賽名額&#xff0c;教練決定把學校信息組的 n 個隊員分成若干個小組去參加這場比賽。 但是每個隊員都…

PLA/PHA生物降解化妝品包裝材料的穩定性與貨架期契合性研究

更多案例&#xff1a;https://npmatc.niicapm.com/ 在可持續發展理念的推動下&#xff0c;化妝品行業正經歷一場綠色變革。環保聚合物在包裝領域的應用已成為重要趨勢&#xff0c;這不僅源于消費者對生態友好產品的需求&#xff0c;更基于全球塑料污染治理的緊迫性。化妝品包裝…

STM32[筆記]--4.嵌入式硬件基礎

4.嵌入式硬件基礎 4.1認識上官二號開發板 主控芯片:STM32F103C8T6高速晶振:8M低速晶振:32.768kLED:5顆KEY:3個 主控芯片內部的資源如下項目介紹內核Cortex-M3Flsah64K*8bitSRAM20K*8bitGPIO37個GPIO,分別為PA0-PB15,PC13-PC15,PD0-PD1ADC2個12bitADC合計12了通道,外部通…

【LLaMA-Factory 實戰系列】一、數據準備篇 - 從文本到多模態的完整流程

【LLaMA-Factory 實戰系列】一、數據準備篇 - 從文本到多模態的完整流程 1. 引言2. LLaMA-Factory 數據格式概述2.1 Alpaca 格式2.2 ShareGPT 格式 3. 文本數據準備3.1 Alpaca 格式示例3.2 ShareGPT 格式示例3.3 預訓練數據格式 4. 多模態數據準備4.1 圖像數據準備4.2 視頻數據…

JuiceFS 集群部署詳細指南:使用 SeaweedFS 作為數據存儲,ETCD 作為元數據存儲

1. 概述 本指南將詳細介紹如何部署一個 JuiceFS 集群,其中數據存儲層采用高性能的分布式對象存儲 SeaweedFS,元數據存儲層采用強一致性的分布式鍵值存儲 ETCD。這種組合方案旨在為用戶提供一個高性能、高可用、易于擴展且數據強一致的分布式文件系統解決方案,特別適用于云原…

【數字后端】- 什么是NDR規則?

NDR是指與工藝庫的默認規則&#xff08;DR&#xff09;不同的特殊物理規則&#xff1a; 常見的有&#xff1a; 間距規則&#xff08;spacing&#xff09;&#xff1a;增加信號線與鄰近線之間的距離&#xff0c;降低Crosstalk串擾。線寬規則&#xff08;width&#xff09;&…

B2B 商城定制的優勢:解鎖企業數字化轉型新動力

精準適配業務流程&#xff0c;貼合企業運營特色? 每一家企業都有獨特的業務流程、運營模式與管理需求。標準化的 B2B 商城往往難以完全滿足企業個性化的業務需求&#xff0c;而定制化商城則能夠深入剖析企業業務細節&#xff0c;從采購、銷售、庫存管理到財務管理等全流程&am…

osg實例繪制

#include <osg/Geometry> #include <osg/Geode> #include <osg/Program> #include <osg/VertexAttribDivisor> #include <osgViewer/Viewer> #include <osgViewer/ViewerEventHandlers> #include <random> // 創建單個立方體幾何體&…

Qt面試題匯總

目錄 1. 簡單說一下Qt 2. 用過QT中的哪些模塊&#xff1f; 3. 說一些你常用的Qt控件&#xff1f; 4. Qt中如何創建一個窗口&#xff1f; 5. 說一下QT中創建控件的方式? 6. 說一下Qt中信號和槽機制是什么&#xff1f; 7. 說一下QT信號與槽機制原理&#xff1f; 8. 如何自…

【stm32】標準庫學習——USART串口

目錄 一、USART串口 1.串口參數及時序 2.USART簡介 3.配置USART基本結構 4.初始化模板 (1) 接收一個數據 (2) 發送一個數據 一、USART串口 1.串口參數及時序 波特率:串口通信的速率起始位:標志一個數據幀的開始&#xff0c;固定為低電平數據位:數據幀的有效載荷&#…

黑馬Day01-03集開始

03集 JSX jsx里面可以寫 表達式,表達式里面會返回一個值js語法的擴展,需要babel解析才能夠在瀏覽器運行 語法 使用花括號 {} ,在里面進行編寫jsx代碼04集 高頻場景 使用引號傳遞字符串 使用js變量 函數調用和方法調用 使用js對象.js自帶的一些對象或new出來的對象{&quo…

vue 路由學習

params 不能傳遞對象類型如 [ ]和{ } query傳參 總結&#xff1a; query傳參既可以通過name 和path 找到路由規則里的組件&#xff0c;所以為了統一避免非必要麻煩 無論是使用query傳參還是 params傳參 映射路由建議統一使用 name 進階 props的使用 備注&#xff1a;資料來自…

JDK安裝全攻略:開啟Java編程大門

目錄 一、安裝前準備1.1 確認系統類型1.2 檢查系統要求1.3 下載 JDK 安裝包 二、Windows 系統下 JDK 安裝步驟2.1 雙擊安裝包2.2 選擇安裝目錄2.3 完成安裝 三、Windows 系統環境變量配置3.1 打開環境變量設置3.2 配置 JAVA_HOME 變量3.3 配置 Path 變量3.4 驗證配置 四、Linux…

《P1253 扶蘇的問題》

題目描述 給定一個長度為 n 的序列 a&#xff0c;要求支持如下三個操作&#xff1a; 給定區間 [l,r]&#xff0c;將區間內每個數都修改為 x。給定區間 [l,r]&#xff0c;將區間內每個數都加上 x。給定區間 [l,r]&#xff0c;求區間內的最大值。 輸入格式 第一行是兩個整數&…

09.【C語言學習筆記】指針(一)

目錄 1. 內存和地址 1.1 內存 1.2 究竟該如何理解編址 2. 指針變量和地址 2.1 取地址操作符&#xff08;&&#xff09; 2.2 指針變量和解引用操作符&#xff08;*&#xff09; 2.2.1 指針變量 2.2.2 如何拆解指針類型 2.2.3 解引用操作符 * 2.3 指針變量的大小…

Java中static關鍵字的作用與使用詳解

static是Java中一個非常重要的關鍵字&#xff0c;它可以用來修飾變量、方法、代碼塊和嵌套類。下面將從多個方面詳細解釋static的作用和使用方法。 一、static變量&#xff08;類變量&#xff09; 作用 static變量屬于類&#xff0c;而不是類的某個實例。所有實例共享同一個s…

HMLDM-UD100A 型工業激光測距儀通過modbusRTU 轉 profinet 網關輕松接入到西門子1200plc

HMLDM-UD100A 型工業激光測距儀通過modbusRTU 轉 profinet 網關輕松接入到西門子1200plc 在現代工業生產與自動化控制領域&#xff0c;精準的測量設備與高效的通信技術至關重要。HMLDM-UD100A 型工業激光測距儀憑借其高精度、穩定性強等優勢&#xff0c;廣泛應用于各類工業場景…

數據結構與算法:圖論——深度優先搜索dfs

深度優先搜索dfs 提到深度優先搜索&#xff08;dfs&#xff09;&#xff0c;就不得不說和廣度優先搜索&#xff08;bfs&#xff09;有什么區別 根據搜索方式的不同&#xff0c;可以將圖的遍歷分為「深度優先搜索」和「廣度優先搜索」。 深度優先搜索&#xff1a;從某一頂點出…