Python實用技法第17篇:將名稱映射到序列的元素中

1、需求

我們的代碼是通過位置(即索引或下標)來訪問列表會元組的,但有時候這會讓代碼變得有些難以閱讀。我們希望可以通過名稱來訪問元素,以此減少結構中對位置的依賴性。

2、解決方案

相比普通的元組,collections.namedtuple()(命名元組)只增加了極少的開銷就提供了這些便利。實際上collections.namedtuple()是一個工廠方法,它返回的是Python中標準元組類型的子類。我們提供給它一個類型名稱以及相應的字段,它就返回一個可實例化的類、爲你已經定義好的字段傳入值等。

from collections import namedtuple
Subscriber=namedtuple('Subsciber',['addr','joined'])
sub=Subscriber("[email protected]","2018-10-23")

print(sub)
print(sub.addr)
print(sub.joined)

print(len(sub))
addr,joined=sub
print(addr)
print(joined)

#下面錯誤,因爲namedtuple是不可變的
#sub.joined="2019"
Python資源分享qun 784758214 ,內有安裝包,PDF,學習視頻,這裏是Python學習者的聚集地,零基礎,進階,都歡迎

結果:

Subsciber(addr='[email protected]', joined='2018-10-23')
[email protected]
2018-10-23
2
[email protected]
2018-10-23

儘管namedtuple的實例看起來就像一個普通的類實例,但它的實例與普通的元組是可互換的,而且支持所有普通元組所支持的操作。

命名元組的主要作用在於將代碼同它所控制的元素位置間解耦。所以,如果從數據庫調用中得到了一個大型的元組列表,而且通過元素的位置來訪問元素,那麼假如在表單中新增了一列數據,那麼代碼就會崩潰,但如果首先將返回的元組轉換爲命名元組,就不會出現問題。

爲了說明這個問題,下面有一些使用普通元組的代碼:

def compute_cost(records):
    total=0.0
    for rec in records:
        total+=rec[1]*rec[2]
    return total

通過位置來引用元素常常使得代碼的表達力不夠強,而且也很依賴於記錄的具體結構。

下面是使用命名元組的版本:

from collections import namedtuple
Stock=namedtuple('Stock',['name','shares','price'])
def compute_cost(records):
    total=0.0
    for rec in records:
        s=Stock(*rec)
        total+=s.shares*s.price
    return total

3、分析

namedtuple的一種可能用法是作爲字典的替代,後者需要更多的空間來存儲。因此,如果要構建設計字典的大型數據,使用namedtuple會更加高效,但是請注意,與字典不同的是,namedtuple是不可變的。

如果需要修改任何屬性,可以通過使用namedtuple實例_replace()方法來實現。該方法會創建一個全新的命名元組,並對相應的值做替換。

from collections import namedtuple
Subscriber=namedtuple('Subsciber',['addr','joined'])
sub=Subscriber("[email protected]","2018-10-23")

print(sub)

sub=sub._replace(joined="2018-10-24")
print(sub)

結果:

Subsciber(addr='[email protected]', joined='2018-10-23')
Subsciber(addr='[email protected]', joined='2018-10-24')

_replace()方法有一個微妙的用途,那就是它可以作爲一種簡單的方法填充具有可選或缺失字段的命名元組。要做到這點,首先創建一個包含默認值得原型數組,然後使用_replace()方法創建一個新的實例,把相應的值替換掉。

from collections import namedtuple
Subscriber=namedtuple('Subsciber',['addr','joined','age'])
sub=Subscriber("",None,0)

def dict_to_stock(s):
    return sub._replace(**s)

a={"addr":"[email protected]","joined":"1111-11-11","age":11}
a=dict_to_stock(a)
print(a)

b={"addr":"[email protected]","joined":"1111-11-11"}
b=dict_to_stock(b)
print(b)

結果:

Subsciber(addr='[email protected]', joined='1111-11-11', age=11)
Subsciber(addr='[email protected]', joined='1111-11-11', age=0)
Python資源分享qun 784758214 ,內有安裝包,PDF,學習視頻,這裏是Python學習者的聚集地,零基礎,進階,都歡迎

最後,也是相當重要的是,應該要注意如果我們的目標是定義一個高效的數據結構,而且將來會修改各種實例屬性,那麼使用namedtuple並不是最佳選擇,相反,可以考慮頂一個使用了slots屬性的類。

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