使用命名元組編寫簡潔的Python代碼

使用命名元组编写简洁的Python代码

命名元組:namedtuple,是Python語言裡沒有引起足夠重視的一種數據類型。這是Python中容易被忽略的神奇功能之一。

當您需要定義一個類時,namedtuple是一個很好的選擇。關於命名元組的一些有趣的功能,我會在本文中向您一一介紹。

那麼,什麼是命名元組以及它有什麼特性?我們可以把namedtuples看作是Python內置的元組數據類型的擴展。

Python的元組是一種用於對任意對象進行分組的簡單數據結構。元組的內容是不可變的,一旦被創建,數據元素就不能被修改。如下:

使用命名元组编写简洁的Python代码

元組有一個缺點,存儲在其中的數據只能通過索引來訪問。你不能對存儲在元組中的單個屬性進行命名。這會影響代碼的可讀性。 而且,元組通常是一個ad-hoc結構。你很難確保兩個元組存儲有相同數量的字段和相同的屬性。這使得當混合字段順序時很容易引入“slip-of-the-mind”的bug。

Namedtuples解決的問題

Namedtuples主要用來解決如下兩個問題。

首先,namedtuples和常規元組一樣,它的內容是不可改變的。 一旦你將數據存儲在其中,就不能再修改。

除此之外,命名元組也是,命名的元組。可以通過唯一的標識符來訪問存儲在其中的對象。您不必記住元素的下標索引,也不必為了記憶方便把索引定義為常量。

一個典型的命名元組如下所示:

使用命名元组编写简洁的Python代码

使用命名元組前需要先導入collections模塊。Python 2.6的標準庫中即包含。在上面的例子裡,定義了一個簡單的命名元組數據類型:“Car”,包含“color” 和“mileage”兩個字段。

也許你你會發現上面的語法有一點怪:為什麼我們把兩個字段寫為一個字符串“color mileage”?

答案是因為命名元組的工廠函數會在字段字符串後默認調用split函數對字段進拆解。所以上面的寫法就是下面寫法的快捷方式:

使用命名元组编写简洁的Python代码

當然如果你喜歡的話,你也可以直接把字段寫成列表形式。這樣寫的優點是,把字段使用多行分隔,利於代碼格式化。

使用命名元组编写简洁的Python代码

接下來,你就可以使用“Car”的工廠函數創建"car"對象了,就像你創建一個類對象“Car”,並且創建了參數值為“color” 和“mileage”的構造函數。

使用命名元组编写简洁的Python代码

元組的解包以及帶有*函數參數的解包也可正常工作。

使用命名元组编写简洁的Python代码

命名元組中元素的即可以通過ID來訪問,也可以通過其索引來訪問。這樣命名元組可以直接替代常規的元組。

使用命名元组编写简洁的Python代码

命名元組的輸出甚至可以是一個標準的字符串表達式,如下,這樣省去了不少的輸入冗餘。

使用命名元组编写简洁的Python代码

像元組一樣,命名元組的內容也是不可修改的。當你試圖重寫其中字段值時,系統會拋出AttributeError異常:

使用命名元组编写简洁的Python代码

在Python內部,命名元組是通過一個常規的類對象實現的。但是在內存使用效率上比常規類要高,和正常元組一樣。

你可以把命名元組看做是一個自定義的不可修改的類的快捷方式,但是更節約內存。

命名元組的子類

因為命名元組是在常規類的基礎上構建的,所以你也可以添加方法到命名元組的類中。舉個例子,你通過可以添加方法和屬性擴展這個類,和擴展常規的類一樣。例子如下:

使用命名元组编写简洁的Python代码

我們可以創建對象MyCarWithMethods,並且定義一個 hexcolor方法,結果如下

使用命名元组编写简洁的Python代码

這個方法可能看起來有點笨拙。但是當你想得到一個不可修改的類時可以這麼試一下。但是注意別搬起石頭砸了自己的腳!

舉個例子,由於命名元組的內部構建機制,添加一個新的不可改變的字段是比較麻煩的。最簡單的方法就是利用基本元組的._field屬性。

使用命名元组编写简洁的Python代码

結果如下:

使用命名元组编写简洁的Python代码

內置幫助函數

除了._fields屬性,每個命名元組實例還內置了一些非常有用的幫助函數。這些函數都以下劃線開頭,通常用下劃線開頭表示它們是私有的方法或者屬性,不屬於類或者模塊的公共接口。

在命名元組中這些以下劃線命名的函數方法則有不同的含義:這些幫助函數或者屬性是命名元組公共接口的一部分。之所以這麼命名是為了避免和用戶自定義的元組字段衝突。您可以隨意使用這些幫助函數。

下面我會給大家展示一些十分有用的命名元組的幫助函數,我們以 _asdict 函數為例,此函數返回值是一個字典,字典內容是命名元組中存儲的元素,如下:

使用命名元组编写简洁的Python代码

當你使用JSON樣式的輸出時,這個函數能避免輸入錯誤,相當有用,舉例如下:

使用命名元组编写简洁的Python代码

另一個有用的幫助函數是 _replace ,它會生成當前元組的一個副本(淺拷貝),並且允許用戶對其中字段進行選擇性替換。

使用命名元组编写简洁的Python代码

最後,_make類方法可以用來在序列或者迭代中創建一個新的命名元組實例,如下:

使用命名元组编写简洁的Python代码

什麼時候使用命名元組

命名元組是使您的代碼變得簡潔有效的一個簡單快速的方法。它通過更好的結構化數據也增強了代碼的可讀性。

舉個例子,我發現把有混合數據的字典這樣的 ad-hoc數據類型用命名元組來代替,能夠更清楚的表達我的意圖。當我把數據作為命名元組重構時,代碼中面臨的一些問題,總能找到意想不到的解決辦法。

使用命名元組處理非結構化的元組和字典,也會讓我的同事們工作變的輕鬆,因為函數直接傳遞的數據是“自解釋的”,非常容易理解(在某種程度上)。

另一方面,如果命名元組無法使您的代碼變得更簡潔,更易讀,可維護性更高,我就不建議使用它們。因為“一件事太好的話可能就是壞事了”。

但是,如果您謹慎的使用命名元組的話,無疑會使您的代碼更好,更富有表現力。

需要記住的事項

  • collection.namedtuple,是一個自定義的不可修改的類的快捷方式,但是更節約內存。

  • 命名元組通過更容易讓人理解的方式結構化您的數據,使您的代碼更乾淨整潔。

  • 命名元組提供了一些十分有用的以下劃線開頭幫助函數,您可以放心使用它們。

英文原文:https://dbader.org/blog/writing-clean-python-with-namedtuples
譯者:少年


分享到:


相關文章: