目錄
一、緒論
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(typename, field_names, *, verbose=False, rename=False, module=None)
namedtuple,顧名思義是已具命名的元組 (簡稱具名元組),它返回一個 tuple 子類。
其中,namedtuple 名稱爲參數 typename,各字段名稱爲參數 field_names。
其中,field_names 既可以是一個類似 ['x', 'y'] 的字符串序列 (string-seq),也可以是用空格或逗號分隔開的純字符串 string,如 'x y' 或 'x, y'。任何 Python 的有效標識符都可作爲字段名。所謂有效標識符由字母,數字,下劃線組成,但首字母不能是數字或下劃線,且不能與 Python 關鍵詞重複,如 class, for, return 等。
具名元組 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》