1. 程式人生 > >[python][collections] namedtuple 命名元組

[python][collections] namedtuple 命名元組

關於 collections 模組

python 自帶的一些資料型別已經非常實用了,但在一些情況下,原生的資料結構並不能滿足我們的需求。而在 python 中,想從底層定義一種資料型別又特別困難。因此, python 在它的 collections 模組中又為我們提供了幾種新的資料型別,靈活的使用它們將會提升我們編寫程式的效率。

1. 為什麼要用命名元組

很多時候,我們需要用比較規範的形式將資料組織在一起,而對於簡單的資料,使用結構體就有一些大材小用了。這個時候, namedtuple 這個類就可以很好地幫我們解決這一個問題。

2. 定義元組

命名元組的定義方式是: namedtuple(typename, field_names)

,其中 typename 是這一種命名元組的名字,而 field_names 是元素對應的名稱,而且它可以為下面的任意一種形式:

  • ['x', 'y']

  • 'x y'

  • 'x, y'

介紹了申明的方法了之後,我們就拿一個最簡單的例子來實戰一下。在 python 程式中,我們經常用到“點”這樣的型別,而這種時候命名元組的便捷性就體現出來了。

from collections import namedtuple
p = namedtuple('Point', ['x', 'y'])

這樣,我們就定義了一種新的命名元組,接下來我們就可以使用它了。

3. 使用元組

接下來,我們用定義好的命名元組建立兩個新的元組:

a = p(1, 2)
b = p(x=3, y=4)
print(a)

可以看到,初始化命名元組時,直接賦值與關鍵字賦值都是可以的,而這一段程式的輸出結果是:

Point(x=1, y=2)

前面的 Point ,就是我們剛剛標記的命名元組名稱。這樣就說明 ab 這兩個變數已經是 Point 型別的了。此時,我們試一下求一下這兩個點之間的距離。

dis = lambda a, b : ((a.x - b.x) ** 2 + (a.y - b.y) ** 2) ** 0.5
print(dis(a, b))
2.8284271247461903

可以看到,這個時候我們就可以通過 a.x

這樣的形式訪問命名元組中的元素了。當然,我們還是可以像之前一樣,使用 a[0] 來獲取第一個元素。

4. 將一個列表匯入到命名元組

有些時候,我們想將一個列表匯入到命名元組中,這個時候我們就可以使用 _make() 方法來完成。

l = [1, 2]
a = p._make(l)
print(a)
Point(x=1, y=2)

有些時候,將列表轉化為命名元組,會更有利於資料的處理,因此要靈活使用這一項功能。

5. 修改命名元組的值

標題看上去很令人疑惑--一個元組的值怎麼能被修改呢。其實所謂的“修改”,就是新建一個修改後的元組,替換原有的元組,這樣相當於間接地完成了元組的修改。而這一個功能可以通過內建方法 _replace() 來實現。

a = p(x=1, y=2)
a._replace(x=3)
print(a)
Point(x=3, y=2)

這樣通過內建方法,我們就可以去“修改”命名元組的值了。

6. 命名元組的巢狀

比方說,我之前定義了一個命名元組叫 Point,而我現在想要定義一個正方形 Square ,它由 x, y, a 組成。那麼這個時候,我們能否套用之前 Point 的定義,去組合出 Square 這個型別呢?

這當然是可以的,當我們使用命名元組的 _fields 這一個屬性時,它將會返回這個元組組成的元素名稱。

>>> p._fields
('x', 'y')

而將這個返回值用於定義新命名元組時的引數設定,我們也就實現了命名元組的巢狀:

sq = namedtuple('Square', p.fields + ('a',))
s = sq(1, 1, 4)
print(s)
Square(x=1, y=1, a=4)

這樣我們就實現了一個正方形的定義。那我們能不能用另方法,去定義實現一種新的命名元組"矩形" Rectangle ,它由兩組 xy 座標組成呢?

rect = namedtuple('Rectangle', p._fields * 2)
Encountered duplicate field name: 'x'

可以看到,它提示我們有重複的屬性 x ,因為命名元組要求引數唯一,這也是命名元組相較於結構體的一個缺陷。這時我們只能老老實實的用不同的變數名了。。。

rect = namedtuple('Rectangle', 'x1 y1 x2 y2')
r = rect(0, 0, 4, 4)
print(r)
Rectangle(x1=0, y1=0, x2=4, y2=4)

結語

正確地使用 namedtuple 可以使我們的程式碼變得更加直觀,並且相較於結構體,它的定義更加的輕量化。不過當然,在某些情況下,我們還是需要使用結構體來完成更復雜的操作。因此我們在程式設計時應當作出合理的選擇,這樣才能發揮 python 最大的效率。