Python進(jìn)階1-元組和列表

本系列文章是一系列學(xué)習(xí)筆記,希望較為深入地分析Python3中的原理、性能,文章中絕大部分觀點(diǎn)都是原作作者的觀點(diǎn)(如下),本人對書中示例加以實(shí)踐和總結(jié),并結(jié)合相應(yīng)的Python的C語言源碼(3.6.1),分享出來。原著:

  • 《High Performance Python》by O'Relly Media,作者M(jìn)icha Gorelick,Ian Ozsvald
  • 《Fluent Python》by O'Relly Media,作者Luciano Ramalho

深入理解各種序列(元組、列表等)能阻止我們不要重復(fù)造輪子。

序列的分類

常見的分類一般按照Mutable和Immutable分類,還可以按照:
Container sequence(元素為對象的序列):List,Tuple,collections.deque
Flat sequence(緊湊序列):str,bytes,bytearray,memoryview,array.array

列表List

List:動態(tài)數(shù)組,元素可變,可改變大?。╝ppend,resize)
列表是很容易掌握的,說一些重點(diǎn)的操作。

列表推導(dǎo)(List Comprehensions)和生成器(Generator)

列表推導(dǎo)和生成器是創(chuàng)建列表和其他序列的快速方法,能夠?qū)懗龊喗榍腋咝阅艿拇a。

>>> dummy = [x for x in 'ABC']
>>> dummy
['A', 'B', 'C']

map和filter也能快速創(chuàng)建列表,但是在性能上并沒有優(yōu)勢:

(env) MengdeiMac:02-array-seq an$ cat listcomp_speed.py 
import timeit

TIMES = 10000

SETUP = """
symbols = '$¢£¥€¤'
def non_ascii(c):
    return c > 127
"""

def clock(label, cmd):
    res = timeit.repeat(cmd, setup=SETUP, number=TIMES)
    print(label, *('{:.3f}'.format(x) for x in res))

clock('listcomp        :', '[ord(s) for s in symbols if ord(s) > 127]')
clock('listcomp + func :', '[ord(s) for s in symbols if non_ascii(ord(s))]')
clock('filter + lambda :', 'list(filter(lambda c: c > 127, map(ord, symbols)))')
clock('filter + func   :', 'list(filter(non_ascii, map(ord, symbols)))')
(env) MengdeiMac:02-array-seq an$ python listcomp_speed.py 
listcomp        : 0.012 0.013 0.013
listcomp + func : 0.017 0.018 0.032
filter + lambda : 0.020 0.016 0.025
filter + func   : 0.015 0.020 0.025

創(chuàng)建元組、arrays等序列時(shí),也可以通過列表推導(dǎo)來做,但是使用生成器可以更加節(jié)省內(nèi)存。(通過iterator protocal生成元素,而不是全部生成放在內(nèi)存里)

元組Tuple

** 元組不僅僅是“不可修改的列表”(Immutable List)**
** 元組也可以被用作“無屬性的記錄”(Records with no field name)**

Tuple as Records

如果只是把元組看作不可變的列表,那么元素的順序并不是很重要。我們可以把元組看作一系列的屬性,屬性的數(shù)量是固定的,位置也是重要的。

(name, age)  = ('Jack', 18)

我們可以通過位置獲取相應(yīng)的屬性,書中還介紹了Named Tuple,collections .nametuple,可以賦予屬性名字,可以通過名字或位置來訪問屬性,比Object更輕量。

Tuple as Immutable List

Tuple支持所有的List的方法,除了add,delete,reverse。
每一個(gè)Python程序員都知道,序列可以切片,像這樣a[start:stop],一些不那么出名知識點(diǎn)。

為什么slice和range不包括最后一個(gè)元素

  • 這樣更容易得到slice的長度 = stop - start
  • 更容易將序列分割成兩個(gè)部分,a[:3]和a[3:]
 >>> a = [1,2,3,4,5]
>>> a[:3]
[1, 2, 3]
>>> a[3:]
[4, 5]

序列的賦值+=, *=

+= 依賴iadd的實(shí)現(xiàn),也就是inplace addition
*= 依賴imul的實(shí)現(xiàn)
對于可變序列(List),inplace的操作都實(shí)現(xiàn)的很好,對于不可變序列(Tuple),沒有實(shí)現(xiàn)。

>>> l=[1,2,3]
>>> id(l)
4322512072
>>> l *= 2
>>> l
[1, 2, 3, 1, 2, 3]
>>> id(l)
4322512072
>>> 
>>> 
>>> t=(1,2,3)
>>> id(t)
4322621768
>>> t *= 2
>>> t
(1, 2, 3, 1, 2, 3)
>>> id(t)
4322550888
>>> 

也就是,對于一個(gè)不可變序列, 重復(fù)的粘貼操作是非常低效的,伴有很多的內(nèi)存分配和拷貝操作。
還有一個(gè)corner case,想想輸出是為什么?既拋出異常,tuple也被改變了,結(jié)論就是,不要讓tuple中有可變的對象,疊加賦值操作不是原子操作。

>>> l=(1,2,[30,50])
>>> l[2] += [50,60]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> l
(1, 2, [30, 50, 50, 60])
>>> 

list.sort vs sort

有兩個(gè)排序函數(shù):
列表自帶的函數(shù),list.sort,對一個(gè)列表進(jìn)行原地排序,也就是,不生成一個(gè)新的拷貝。
內(nèi)置的sort函數(shù),sort,創(chuàng)建一個(gè)新的列表,排序,并且返回新列表。

還有一點(diǎn)重要的常識:
functions or methods that change an object in place should return None to make it clear to the caller that the object itself was changed, and no new object was created.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容