日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

python的序列类型及其特点_Fluent Python 笔记——序列类型及其丰富的操作

發(fā)布時(shí)間:2024/7/5 python 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python的序列类型及其特点_Fluent Python 笔记——序列类型及其丰富的操作 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

序列的分類

Python 標(biāo)準(zhǔn)庫(kù)用 C 語(yǔ)言實(shí)現(xiàn)了豐富的序列類型的數(shù)據(jù)結(jié)構(gòu),如:

容器序列(能存放不同類型的數(shù)據(jù)):list、tuple、collections.deque 等

扁平序列(只容納同一類型的數(shù)據(jù)):str、bytes、bytearray、memoryview、array.array

>>> a_list = [1, '2', True, [1, 2, 3], 4.5]

>>> a_str = 'helloworld'

容器序列存放的是對(duì)象的引用,扁平序列存放的是值。即扁平序列是一段連續(xù)的內(nèi)存空間。

>>> a_list = [1, '2', True, [1, 2, 3], 4.5]

>>> embedded_list = a_list[3]

>>> embedded_list

[1, 2, 3]

>>> embedded_list.append(4)

>>> embedded_list

[1, 2, 3, 4]

>>> a_list

[1, '2', True, [1, 2, 3, 4], 4.5]

序列還可以按照是否可變(能夠被修改)進(jìn)行分類:

可變序列:list、bytearray、array.array、collections.deque、memoryview

不可變序列:tuple、str、bytes

>>> a_list = [1, 2, 3]

>>> a_list[0] = 2

>>> a_list

[2, 2, 3]

>>> a_tuple = (1, 2, 3)

>>> a_tuple[0] = 2

Traceback (most recent call last):

File "", line 1, in

TypeError: 'tuple' object does not support item assignment

列表推導(dǎo)

for 循環(huán):

>>> symbols = '!@#$%'

>>> codes = []

>>> for symbol in symbols:

... codes.append(ord(symbol))

...

>>> codes

[33, 64, 35, 36, 37]

列表推導(dǎo):

>>> symbols = '!@#$%'

>>> codes = [ord(symbol) for symbol in symbols]

>>> codes

[33, 64, 35, 36, 37]

通常的原則是,只用列表推導(dǎo)創(chuàng)建新的列表,并盡量保持簡(jiǎn)短。

列表推導(dǎo)(包括集合推導(dǎo)、字典推導(dǎo))、生成器表達(dá)式在 Python3 中有自己的局部作用域。

>>> x = 'ABC'

>>> dummy = [ord(x) for x in x]

>>> x

'ABC'

>>> dummy

[65, 66, 67]

列表推導(dǎo)與 filter/map 的比較:

>>> symbols = '$¢£¥€¤'

>>> beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]

>>> beyond_ascii

[162, 163, 165, 8364, 164]

>>> beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))

>>> beyond_ascii

[162, 163, 165, 8364, 164]

作為記錄的元組

元組其實(shí)是一種數(shù)據(jù)記錄(Record),其中的每個(gè)元素都對(duì)應(yīng)記錄中一個(gè)字段的數(shù)據(jù),字段在元組中的位置則可以用來區(qū)分其含義。

>>> lax_coordinates = (33.9425, -118.408056)

>>> city, year, pop, area = ('Tokyo', 2003, 32450, 8014)

>>> traveler_ids = [('USA', '31195855'), ('BRA', 'CE342567'), ('ESP', 'XDA205856')]

>>> for country, _ in traveler_ids:

... print(country)

...

USA

BRA

ESP

元組拆包

元組拆包可以應(yīng)用到任何可迭代對(duì)象上,唯一的要求即可迭代對(duì)象中的元素?cái)?shù)量與接收這些元素的空檔數(shù)一致(除非用 * 忽略多余的元素)。

元組拆包(平行賦值):

>>> lax_coordinates = (33.9425, -118.408056)

>>> latitude, longitude = lax_coordinates

>>> latitude

33.9425

>>> longitude

-118.408056

不使用中間變量交換兩個(gè)變量的值:

>>> a = 1

>>> b = 2

>>> a, b = b, a

>>> a

2

>>> b

1

使用 * 運(yùn)算符把一個(gè)可迭代對(duì)象拆開作為函數(shù)的參數(shù):

>>> divmod(20, 8)

(2, 4)

>>> t = (20, 8)

>>> divmod(*t)

(2, 4)

元組拆包可以方便一個(gè)函數(shù)以元組的方式返回多個(gè)值,調(diào)用函數(shù)的代碼就可以輕松地(有選擇地)接受這些值。

>>> import os

>>> _, filename = os.path.split('/home/luciano/.ssh/idrsa.pub')

>>> filename

'idrsa.pub'

用 * 處理多余的元素:

>>> a, b, *rest = range(5)

>>> a, b, rest

(0, 1, [2, 3, 4])

>>> a, b, *rest = range(3)

>>> a, b, rest

(0, 1, [2])

>>> a, b, *rest = range(2)

>>> a, b, rest

(0, 1, [])

>>> a, *body, c, d = range(5)

>>> a, body, c, d

(0, [1, 2], 3, 4)

具名元組

collections.namedtuple 可以用來創(chuàng)建一個(gè)帶字段名的元組和一個(gè)有名字的類,便于對(duì)程序進(jìn)行調(diào)試。其類實(shí)例消耗的內(nèi)存與元組是一樣的,跟普通的對(duì)象實(shí)例相比更小一些(不用 __dict__ 存放實(shí)例的屬性)。

>>> from collections import namedtuple

>>> City = namedtuple('City', 'name country population coordinates')

>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))

>>> tokyo

City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))

>>> tokyo.population

36.933

>>> tokyo.coordinates

(35.689722, 139.691667)

>>> tokyo[1]

'JP'

創(chuàng)建具名元組需要傳入兩個(gè)參數(shù),第一個(gè)是類名,第二個(gè)是類的各個(gè)字段的名稱。后者可以是多個(gè)字符串組成的可迭代對(duì)象或由空格分隔開的字段名組成的字符串。

可以通過字段名或位置獲取某個(gè)字段的信息。

具名元組的 _fields 屬性包含由這個(gè)類中所有字段名稱組成的元組;_asdict() 方法可以把具名元組以 collections.OrderedDict 的形式返回。

切片

關(guān)于切片和區(qū)間忽略最后一個(gè)元素

在切片和區(qū)間操作里不包含最后一個(gè)元素是 Python 的風(fēng)格,同時(shí)也符合 C 和其他以 0 為起始下標(biāo)的語(yǔ)言的習(xí)慣。

部分原因如下:

當(dāng)只有最后一個(gè)位置信息時(shí),可以快速看出區(qū)間里包含多少個(gè)元素:range(3) 和 my_list[:3] 都返回 3 個(gè)元素

起止位置都可見時(shí),可以快速算出區(qū)間的長(zhǎng)度(stop - start),如切片 my_list[3:6] 即包含 6 - 3 = 3 個(gè)元素

可以利用任意一個(gè)下標(biāo)把序列分割成不重疊的兩部分(my_list[:x] 和 my_list[x:])

step

可以用 s[a:b:c] 的形式對(duì) s 在 a 和 b 之間以 c 為間隔取值。c 值還可以為負(fù),表示反向取值。

>>> s = 'bicycle'

>>> s[::3]

'bye'

>>> s[::-1]

'elcycib'

>>> s[::-2]

'eccb'

對(duì) seq[start:stop:step] 求值時(shí),Python 會(huì)調(diào)用 seq.__getitem__(slice(start, stop, step))。

對(duì)切片賦值

如果把切片放在賦值語(yǔ)句左邊,或把它作為 del 操作的對(duì)象,則可以對(duì)切片所屬的序列進(jìn)行拼接、切除或就地修改等操作。

>>> l = list(range(10))

>>> l

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> l[2:5] = [20, 30]

>>> l

[0, 1, 20, 30, 5, 6, 7, 8, 9]

>>> del l[5:7]

>>> l

[0, 1, 20, 30, 5, 8, 9]

>>> l[3::2] = [11, 22]

>>> l

[0, 1, 20, 11, 5, 22, 9]

>>> l[2:5] = [100]

>>> l

[0, 1, 100, 22, 9]

需要注意的是,在對(duì)切片進(jìn)行賦值操作時(shí),賦值語(yǔ)句的右側(cè)必須是個(gè)可迭代對(duì)象。

對(duì)序列使用 + 和 *

Python 程序員一般默認(rèn)序列都會(huì)支持 + 和 * 的拼接操作。在拼接過程中,兩個(gè)被操作的序列不會(huì)發(fā)生任何改動(dòng),Python 會(huì)創(chuàng)建一個(gè)新的包含拼接結(jié)果的序列。

>>> l = [1, 2, 3]

>>> l * 5

[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

>>> 5 * 'abcd'

'abcdabcdabcdabcdabcd'

如果 a * n 語(yǔ)句中序列 a 里的元素是對(duì)其他可變對(duì)象的引用的話,這個(gè)式子的結(jié)果可能會(huì)出乎意料。比如用 my_list = [[]] * 3 來初始化一個(gè)有列表組成的列表,實(shí)際上得到的列表里包含的三個(gè)元素是三個(gè)引用,且這三個(gè)引用都指向同一列表。

>>> weird_board = [['-'] * 3] * 3

>>> weird_board

[['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]

>>> weird_board[1][2] = 'O'

>>> weird_board

[['-', '-', 'O'], ['-', '-', 'O'], ['-', '-', 'O']]

其錯(cuò)誤的本質(zhì)等同于如下代碼:

>>> row = ['-'] * 3

>>> board = []

>>> for i in range(3):

... board.append(row)

...

>>> board[1][2] = 'O'

>>> board

[['-', '-', 'O'], ['-', '-', 'O'], ['-', '-', 'O']]

即追加同一個(gè)行對(duì)象(row)到游戲幣(board)

正確的做法代碼如下:

>>> board = [['-'] * 3 for i in range(3)]

>>> board

[['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]

>>> board[1][2] = 'O'

>>> board

[['-', '-', '-'], ['-', '-', 'O'], ['-', '-', '-']]

等同于如下代碼:

>>> board = []

>>> for i in range(3):

... row = ['-'] * 3

... board.append(row)

...

>>> board

[['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]

>>> board[1][2] = 'O'

>>> board

[['-', '-', '-'], ['-', '-', 'O'], ['-', '-', '-']]

即每次迭代中都新建了一個(gè)列表,作為新的一行(row)追加到游戲板子(board)

序列的增量賦值

增量賦值運(yùn)算符 += 和 *= 的行為取決于第一個(gè)操作對(duì)象。

+= 調(diào)用的特殊方法是 __iadd__(自增)。如果某個(gè)類沒有實(shí)現(xiàn)該方法,Python 會(huì)退一步調(diào)用 __add__。

如 a += b 就會(huì)調(diào)用 a 中實(shí)現(xiàn)的 __iadd__ 方法,同時(shí)對(duì)于可變序列(如 list、bytearray、array.array),該方法的行為類似于 a.extend(b),在 a 上就地改動(dòng)。

如 a 沒有實(shí)現(xiàn) __iadd__,a += b 的效果就類似于 a = a + b,計(jì)算 a + b 得到一個(gè)新的對(duì)象,再把這個(gè)對(duì)象賦值給 a。

*= 對(duì)應(yīng)的是 __imul__。

>>> l = [1, 2, 3]

>>> id(l)

2888988078920

>>> l *= 2

>>> l

[1, 2, 3, 1, 2, 3]

>>> id(l)

2888988078920

>>> t = (1, 2, 3)

>>> id(t)

2888988799688

>>> t *= 2

>>> id(t)

2888988107592

作為可變對(duì)象的列表運(yùn)用增量乘法后,ID 沒變;而作為不可變對(duì)象的元組運(yùn)用增量乘法后,新的元組被創(chuàng)建。

因此對(duì)于不可變序列做重復(fù)拼接操作效率會(huì)很低,每次都會(huì)有一個(gè)新對(duì)象。但字符串除外,由于對(duì)字符串做 += 等操作太普遍,CPython 專門做了優(yōu)化。在為字符串初始化內(nèi)存時(shí),程序會(huì)預(yù)留額外的可擴(kuò)展空間。

list.sort 與 sorted

list.sort 方法會(huì)就地排序列表,即在原列表的基礎(chǔ)上完成排序,不會(huì)再另外復(fù)制一份。也因此其返回值為 None。

內(nèi)置的 sorted 函數(shù)則會(huì)新建一個(gè)列表作為返回值。它可以接收任何形式的可迭代對(duì)象(包含不可變序列和生成器),最后返回的始終是排序好的列表。

>>> fruits = ['grape', 'raspberry', 'apple', 'banana']

>>> sorted(fruits)

['apple', 'banana', 'grape', 'raspberry']

>>> fruits

['grape', 'raspberry', 'apple', 'banana']

>>> sorted(fruits, key=len)

['grape', 'apple', 'banana', 'raspberry']

>>> fruits

['grape', 'raspberry', 'apple', 'banana']

>>> fruits.sort()

>>> fruits

['apple', 'banana', 'grape', 'raspberry']

參考資料

總結(jié)

以上是生活随笔為你收集整理的python的序列类型及其特点_Fluent Python 笔记——序列类型及其丰富的操作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。