【Python】詳解 collections.namedtuple

目錄

一、緒論

二、namedtuple 函數

2.1 說明


一、緒論

collections 作爲 Python 的內建集合模塊,實現了許多十分高效的特殊容器數據類型,即除了 Python 通用內置容器: dict、list、set 和 tuple 等的替代方案。在 IDLE 輸入 help(collections) 可查看幫助文檔,其中常見的類/函數如下:

名稱 功能
namedtuple 用於創建具有命名字段的 tuple 子類的 factory 函數 (具名元組)
deque 類似 list 的容器,兩端都能實現快速 append 和 pop (雙端隊列)
ChainMap 類似 dict 的類,用於創建多個映射的單視圖
Counter 用於計算 hashable 對象的 dict 子類 (可哈希對象計數)
OrderedDict 記住元素添加順序的 dict 子類 (有序字典)
defaultdict dict 子類調用 factory 函數來提供缺失值
UserDict 包裝 dict 對象以便於 dict 的子類化
UserList 包裝 list 對象以便於 list 的子類化
UserString 包裝 string 對象以便於 string 的子類化

而本文詳述的對象爲具名/命名元組 —— namedtuple 。  


二、namedtuple 函數

Python 內建普通元組 tuple 存在一個侷限,即不能爲 tuple 中的元素命名,故 tuple 所要表達的意義並不明顯。

因此,引入一工廠函數 (factory function) collections.namedtuple,以構造一個帶字段名的 tuple。具名元組 namedtuple 的實例和普通元組 tuple 消耗的內存一樣多 (因爲字段名都被保存在對應的類中) 但卻更具可讀性 (namedtuple 使 tuple 變成自文檔,根據字段名很容易理解用途),令代碼更易維護;同時,namedtuple 不用命名空間字典(namespace dictionary) __dict__ 來存放/維護實例屬性,故比普通 dict 更加輕量和快速。但注意,具名元組 namedtuple 繼承自 tuple ,其中的屬性均不可變

2.1 說明

collections.namedtuple(typenamefield_names*verbose=Falserename=Falsemodule=None)

namedtuple,顧名思義是已具命名的元組 (簡稱具名元組),它返回一個 tuple 子類。

其中,namedtuple 名稱爲參數 typename,各字段名稱爲參數 field_names

其中,field_names 既可以是一個類似 ['x', 'y'] 的字符串序列 (string-seq),也可以是用空格或逗號分隔開的純字符串 string,如 'x y' 或 'x, y'。任何 Python 的有效標識符都可作爲字段名。所謂有效標識符由字母,數字,下劃線組成,但首字母不能是數字或下劃線,且不能與 Python 關鍵詞重複,如 classforreturn 等。

具名元組 namedtuple 向後兼容普通 tuple,從而既可通過 field_names 獲取元素值/字段值,也能通過索引和迭代獲取元素值/字段值。

>>> from collections import namedtuple

# Point = namedtuple("Point", 'x, y')  # 等價的初始化方式
# Point = namedtuple("Point", 'x y')   # 等價的初始化方式
>>> Point = namedtuple("Point", ['x', 'y'])  # 初始化一個具名元組 Point
>>> Point
<class '__main__.Point'>
# -------------------------------------------------------------------------
>>> p1 = Point(2, 3)  # 實例化一個具名元組 Point 對象 p1
>>> p1                # 可讀 (readable __repr__ with a name=value style)
Point(x=2, y=3)
# -------------------------------------------------------------------------
>>> p1.x   # 通過字段名獲取元素值/字段值 (fields also accessible by name)
2
>>> p1[0]  # 通過索引獲取元素值/字段值 (indexable like the plain tuple (2, 3))
2
>>> for i in p1:  # 通過迭代獲取元素值/字段值
	print(i)
2
3
# -------------------------------------------------------------------------
>>> a, b = p1  # 能夠像普通 tuple 一樣解綁 (unpack like a regular tuple)
>>> a, b
(2, 3)

除繼承普通 tuple,具名元組 nametuple 還額外支持三個方法和兩個屬性。爲防止名稱衝突,方法和屬性以下劃線開始:

  • 類屬性 _fields:包含本類所有字段名的元組 tuple
  • 類方法 _make(iterable):接受一個序列 sequence 或可迭代對象 iterable 來生成本類的實例
  • 實例方法 _replace(**kwargs):基於本實例修改、替換元素來生成本類的實例
  • 實例方法 _asdict():將具名元組以 collections.OrdereDict 的形式返回,用於友好地展示元組信息
  • 實例方法 _source:略...
>>> from collections import namedtuple

>>> Point2 = namedtuple("Point2", 'x, y')  # 初始化一個具名元組對象 Point2
>>> p2 = Point2(1, 4)
>>> p2
Point2(x=1, y=4)
# -------------------------------------------------------------------------
>>> p2._fields  # 獲取所有字段名構成的 tuple
('x', 'y')
# -------------------------------------------------------------------------
>>> p21 = p2._make([5, 6])  # 使用 list 實例化一個新 Point2 對象
>>> p21
Point2(x=5, y=6)
>>> p2
Point2(x=1, y=4)  # 原 namedtuple 不變
# -------------------------------------------------------------------------
>>> p22 = p2._replace(y=4.5)  # 使用關鍵字參數修改並實例化一個新 Point2 對象
>>> p22
Point2(x=1, y=4.5)
>>> p2
Point2(x=1, y=4)  # 原 namedtuple 不變
# -------------------------------------------------------------------------
>>> p2._asdict()  # 將 namedtuple 對象轉換爲 OrderedDict 對象
OrderedDict([('x', 1), ('y', 4)])
>>> p2
Point2(x=1, y=4)  # 原 namedtuple 不變

注意,上述方法均非“原地操作” (in-place) 方法,因爲 tuple / namedtuple 是不可變對象!只能創建新的。

若參數 rename=True,無效字段名 field_names  會自動轉換成位置名。例如 ['abc',  'def',  'ghi',  'abc'] 轉換成 ['abc',  '_1',  'ghi',  '_3'],轉換並消除了關鍵詞 def 和重複域名 abc。否則,在創建伊始就會拋出 ValueError。

>>> Point3 = namedtuple("Point3", ['abc', 'def', 'ghi', 'abc'], rename=True)
>>> p3 = Point3(3, 5, 7, 9)
>>> p3._fields
('abc', '_1', 'ghi', '_3')
>>> p3
Point3(abc=3, _1=5, ghi=7, _3=9)

此外,將 dict 轉換爲 namedtuple 可使用雙星操作符 ** (double-star-operator) 進行解包實現:

>>> dict4 = {'x':14, 'y':16}
>>> Point4 = namedtuple("Point4", 'x y')
>>> p4 = Point4(**dict4)
>>> p4
Point4(x=14, y=16)

至於 verbose 參數和 module 參數並不常用,不作贅述。


參考文獻

《Python Immediate》

https://docs.python.org/zh-cn/3.6/library/collections.html?highlight=defaultdict#collections.namedtuple

https://www.runoob.com/note/25726

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章