python 的 tuple 是不是冗余設計?
覺得這個問題挺好,值得好好思考。
Tuple類型對于Python自身來說是非常重要的數據類型,比如說函數調用,實際上會將順序傳入的參數先組成一個tuple;多返回值也是靠返回一個tuple來實現的。因為太常用,所以需要一個更有效的數據結構來提高效率,一個不可變的tuple對象從實現上來說可以比list簡單不少。再比如說code對象會記錄自己的參數名稱列表,free variable名稱列表等等,這些如果用list,就可能被從外部修改,這樣可能導致解釋器崩潰;那就只能選擇改成一個函數每次都返回一個新的列表,這樣又很浪費。所以即使是從解釋器自身實現的角度上來說引入這樣一個不可變的序列類型也是很重要的。
對程序員來說如果沒有什么美學上的追求的話,tuple最大的便利在于它是一個hashable的類型,而且hash算法與值直接對應,這樣在Python里很容易用多個值的組合來做key生成一個dict,比如說我們網絡里有20臺交換機,每個交換機有24個口,那要唯一標識每個口就需要用(交換機ID,口編號),這個tuple可以做dict的key的話,編寫程序起來就很方便了。
Immutable
首先說說Immutable的優勢:
為什么FP在多核時代重獲重視?一個很重要的原因就是FP的Immutable特性。Immutable類型不存在Mutable類型的同步問題;
因為不可變,Immutable類型的內存結構設計就少了很多假設性條件,帶來的直接好處就是性能優化;
Python里只有Immutable類型是Hashable的,因為同樣是Immutable使得Hash Table的設計來得簡單;
業務上不該改變的就不允許其發生中途變化!
immutable的好處實在是太多了:
性能優化,多線程安全,不需要鎖,不擔心被惡意修改或者不小心修改。
Tuple的使用場景
List跟Tuple使用場景上的一點主要區別
看到好多Python程序員都喜歡第一時間就用List,不管合不合適(當然有時候是需要可修改的):
[['張三', 35], ['陳八', 28]]
List存放的數據應該是同質數據;而Tuple呢?其存儲的應該是像數據庫記錄這樣的結構化數據——這個區別是List和Tuple使用上最直白的區別。
所以上述代碼應該改為:
[('張三', 35), ('陳八', 28)]
Tuple是Hashable的
這可以應用在一些有趣的場景,比如把一些“記錄”作為Key:
Out[11]:
[(('張三', 1995), '√ 少林長拳'),
(('張三', 1999), '√ 武當太極'),
(('張三', 2015), '√ 破空神掌'),
(('李七', 2007), '√ 大摔碑手'),
(('李七', 2017), '√ 長空劍法')]
一個武者習武履歷記錄的時間軸就出來了。
此外,其實Python中大量運用Tuple。好比上圖代碼里,在sorted中指定排序順序的字段。然后再看看person.items(),其結構類似上面的輸出,里面同樣藏著Tuple結構。
比如還有print:
In [15]: print("%s is %s." % ('Foo', 'Bar'))
Foo is Bar.
Tuple解構
在上面的print里,其實就是Tuple解構。
比如:
In [28]: name, year = ('張三', 1995)
In [29]: name
Out[29]: '張三'
In [30]: year
Out[30]: 1995
In [31]: for (name, year), gongfu in sorted(person.items(), key=lambda item: (item[0], item[1])):
...: print('{n} -- {y} -- {gf}'.format(n=name, y=year, gf=gongfu))
...:
張三 -- 1995 -- √ 少林長拳
張三 -- 1999 -- √ 武當太極
張三 -- 2015 -- √ 破空神掌
李七 -- 2007 -- √ 大摔碑手
李七 -- 2017 -- √ 長空劍法
Tuple解構特性對于函數返回多值是非常有意義的。
collections.namedtuple具名元組
附帶提提collections.namedtuple,一個工廠函數,其在官方文檔中的定義是:
factory function for creating tuple subclasses with named fields.
Returns a new tuple subclass named?typename. The new subclass is used to create tuple-like objects that have fields accessible by attribute lookup as well as being indexable and iterable...
In [57]: from collections import namedtuple
...:
...: GF = namedtuple('GongFu', 'name, gf, pai, props')
...: data = [
...: GF('張三豐', '太極拳', '武當派', ('男', 60)),
...: GF('劉小七', '八卦掌', '八卦門', ('男', 41)),
...: GF('石破天', '無影手', '無影門', ('男', 39))
...: ]
...: for item in data:
...: print(f'{item.name} -- {item.gf} -- {item.pai} -- {item.props[0]} -- {item.props[1]}.')
...:
張三豐 -- 太極拳 -- 武當派 -- 男 -- 60.
劉小七 -- 八卦掌 -- 八卦門 -- 男 -- 41.
石破天 -- 無影手 -- 無影門 -- 男 -- 39.
collections.namedtuple可以帶上名稱屬性,在邏輯及調試上更加清晰。在作為“記錄”使用時,無疑collections.namedtuple更為合適。而且collections.namedtuple的構建在內存上跟Tuple是一樣的,從而也足夠優化。
而且collections.namedtuple也能夠解構:
In [65]: name, gf, pai, (props0, props1) = data[2]
In [66]: name, gf, pai, props0, props1
Out[66]: ('石破天', '無影手', '無影門', '男', 39)
番外篇
Tuple的一個定義:
Tuple其實是在大量編程語言中得以大量使用的。在一些FP語言中Tuple的基礎其實是Pair,比如Idris中,("Baz", "Foo", "Bar", 39)被當成("Baz", ("Foo", ("Bar", 39)))。
“掃一掃,看一看”
Python
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。