編程學習網 > 編程語言 > Python > Python如何動態獲取和設置對象的屬性?
2025
09-24

Python如何動態獲取和設置對象的屬性?


Python 這個語言吧,有一個特別靈活也特別“陰間”的地方,就是它可以在運行時動態操作對象的屬性。說得直白點,就是你可以隨便加屬性、改屬性、查屬性,甚至刪屬性,而且不報錯,Python 也不會嫌你煩。這在很多靜態語言比如 Java、C++ 那邊根本是不可想象的。

那這事咋做呢?核心其實就兩個函數:getattr() 和 setattr(),再加上一個兄弟 hasattr() 和一個掃地出門用的 delattr(),基本上這幾個組合拳一套下來,對象的屬性你想咋整就咋整。

我第一次意識到這個特性的厲害,是在一個項目里搞動態配置加載的功能。當時業務要求是根據用戶的不同角色,動態地給某個配置類添加屬性。你說這個配置用字典不就完事了?是的,我當時也這么干了,結果后來業務又說,要支持“屬性點語法”,就是 config.user_timeout 這種寫法。我一聽,完了,這不是典型的類屬性訪問嘛,字典不行了。后來我就翻源碼,研究怎么優雅地把字典轉成支持屬性訪問的對象。這時候我才真正體會到 Python 的“魔性”。先說 getattr(obj, attr_name),這個函數你給它一個對象,一個屬性名,它就老老實實地把值給你找出來。如果沒有?它不會報錯,但你可以設個默認值,比如:

這行代碼的意思是,如果 config 有個 user_timeout 屬性,那就用它的值;如果沒有,就用默認的 30。這玩意兒真是做配置讀取的神器,和字典的 .get() 方法有得一拼。

再說 setattr(obj, attr_name, value),這就更野了。你可以直接給對象硬塞一個屬性進去,不管之前有沒有,比如:

執行完這句之后,config.max_retries 就合法了,訪問它就是 5。這種能力在做反射、插件系統、ORM 框架的時候特別有用。比如你寫一個動態表單類,根據表單字段生成對應的屬性,靠的就是這招。我記得我搞一個插件系統的時候,插件有很多自定義配置項,用 YAML 寫的,我一開始還傻傻地一個個手寫,然后突然靈光一閃,直接上 setattr() 循環灌屬性,插件瞬間從“死板”變“活靈活現”。有點像在給對象裝外掛一樣,想怎么改就怎么改。不過呢,setattr() 有個坑,必須得注意:你改的是對象屬性,不是類屬性。而且,如果你用的是 __slots__ 限制的類,那你想隨便加屬性,對不起,加不了,會報錯。這算是 Python 給自由加了個“護欄”,要不然真的誰都能拿對象當字典用了,那多恐怖。還有一個小兄弟叫 hasattr(obj, attr_name),這就是個布爾檢查器,看看屬性存不存在,用來防呆防炸是必須的:

特別是在你處理外部數據,比如 json、數據庫字段、用戶輸入的時候,這種檢查就像安全帶,幫你避免一頭撞南墻。最后一個 delattr(obj, attr_name),這個就比較暴力了,直接把屬性刪掉。它跟 del obj.attr_name 是一樣的,只不過可以動態傳屬性名。這在做緩存失效、清理無用屬性的時候挺方便。那你可能要問了,這幾個東西就這么簡單?為啥能搞出這么多花活兒來?其實背后就是 Python 的對象模型太靈活了。你可以把對象看成一個屬性字典(雖然不完全是,但本質很像),這些函數就是你操作這個“字典”的接口。比如你可以寫個循環,把一堆鍵值對塞進對象里:

這操作跟 obj.__dict__.update(data) 類似,但更安全,而且對 __slots__ 類型的類也更通用一點(當然它會報錯,但你可以 try 一下再 fallback)。

我曾經在給公司搞一個數據同步服務的時候,就用過這個技巧。因為我們從多個第三方系統拉過來的數據字段五花八門,有的系統字段多,有的少,結構還不固定。用傳統的類建模根本 hold 不住,最后我就搞了個“屬性包”對象,靠 setattr() 動態賦值,兼容性杠杠的。

當然了,這種動態屬性的方式,雖然靈活,但也不是沒有代價的。最大的代價就是代碼可讀性差,調試不方便,IDE 提示全靠猜,type checker 直接放棄治療。你用 getattr()、setattr() 多了,別人一看你的代碼就一臉懵逼:“這屬性哪來的?”、“這函數哪兒定義的?”——尤其在多人協作的時候,這就是一把雙刃劍。

所以我的建議是:這種操作,能不用就不用,除非你明確知道自己在干嘛,比如做框架、做底層庫、做 DSL,這種需要高動態能力的場景再用。普通業務開發里,能寫明白的就不要搞花活兒,寫得越動態,出事的可能性就越高。

還有一點,就是性能。動態訪問屬性比直接訪問要慢一丟丟,因為多了一層查找邏輯。雖然差距不是特別大,但在極端高頻場景下,還是能拉開差距的。如果你是搞高性能服務的,尤其是 asyncio 那一掛的,別因為一兩個 getattr() 把延遲拉高了,那可太虧了。

總結一句話:Python 的動態屬性機制確實很香,用得好是大殺器,用不好就是自殺工具。該剛就剛,該動態就動態,別濫用。

行了,今天這點就聊到這兒。下次我有空再跟你們聊聊 __getattr__ 和 __getattribute__,那可是更深一層的魔法操作,簡直可以玩出“代理人”的感覺,攔截所有屬性訪問的請求,像黑客一樣控制一切。但那是進階版,今天先打住,消化一下這些基本功吧。

以上就是“Python如何動態獲取和設置對象的屬性?的詳細內容,想要了解更多Python教程歡迎持續關注編程學習網。

掃碼二維碼 獲取免費視頻學習資料

Python編程學習

查 看2022高級編程視頻教程免費獲取