python (第二章)数据结构
文章目錄
- 2.5 對(duì)序列使用 +和 ×
- 建立由列表組成的列表
- 2.6序列的增量賦值(+=和×=)
- 關(guān)于 +=的謎題
- 補(bǔ)充:extend()方法和+有什么區(qū)別呢?
- 2.7 list.sort方法和內(nèi)置函數(shù)sorted(排序)
- 2.8 用bisect來(lái)管理已排序的序列
- 2.8.2用bisect.insort插入元素
- 2.9 當(dāng)列表不是首選時(shí)
- 2.9.1 數(shù)組
- 2.9.2內(nèi)存視圖
- 2.9.3 NumPy和SciPy
- 2.9.4 雙向隊(duì)列和其他的形式的隊(duì)列
2.5 對(duì)序列使用 +和 ×
l = [1,2,3] print(id(l)) t= l*5 print(id(t))結(jié)果如圖:
- 總結(jié):+ 和 * 都遵循這個(gè)規(guī)律,不修改原有的操作對(duì)象,而是構(gòu)建一個(gè)全新的序列。
- 注意:如果a*n 這個(gè)語(yǔ)句中,序列a里面的元素是對(duì)其他可變對(duì)象的引用的話,這個(gè)結(jié)果可能會(huì)出乎意料。比如,你想用my_list = [[]]*3 來(lái)初始化一個(gè)由列表組成的列表,但是你得到的列表里面包含的3個(gè)元素其實(shí)是3個(gè)引用,而且這3個(gè)引用指向同一個(gè)列表。這顯然不是想要的。
建立由列表組成的列表
正確的方式1:
board = [['_'] * 3 for i in range(3)] print(board) board[1][2] = 'X' print(board)結(jié)果如圖:
錯(cuò)誤的方式1:含有3個(gè)指向同一對(duì)象的引用的列表是毫無(wú)用處的。
weird_board = [['_']*3] *3 print(weird_board) weird_board[1][2] = '0' print(weird_board)結(jié)果如圖:
錯(cuò)誤的方式2:
這個(gè)和上一個(gè)錯(cuò)誤的本質(zhì)是一樣的
結(jié)果如圖:
正確的方式2:
這里的等同于正確的方式1
結(jié)果如圖:
2.6序列的增量賦值(+=和×=)
增量賦值運(yùn)算符+=和*=的表現(xiàn)取決于它們的第一個(gè)操作對(duì)象,本次的就集中討論(+=)。對(duì)其他的增量運(yùn)算符也同樣適用。
+=背后的特殊方法是__iadd__(用于‘就地加法’),所謂的‘就地’理解為:不創(chuàng)建新的對(duì)象,而是將原來(lái)的對(duì)象重新賦值。如果一個(gè)類沒(méi)有實(shí)現(xiàn)這個(gè)方法的話,python會(huì)退一步調(diào)用__add__.
我們考慮下面這個(gè)簡(jiǎn)單的表達(dá)式:
-
a+=b
-
討論:
(1).若a實(shí)現(xiàn)了__iadd__方法,就會(huì)調(diào)用這個(gè)方法。同時(shí)對(duì)于可變序列(list,bytearray和array.array)來(lái)說(shuō),a會(huì)就地變動(dòng)了,就像調(diào)用了a.extend(b)一樣
(2).若a沒(méi)有實(shí)現(xiàn)__iadd__方法,a+=b這個(gè)表達(dá)式的效果就會(huì)根a=a+b一樣了;首先計(jì)算a+b,得到一個(gè)新的對(duì)象,然后賦值給a。 -
總結(jié):
在這個(gè)表達(dá)式中,變量名會(huì)不會(huì)被關(guān)聯(lián)到新的可變對(duì)象,完全取決于這個(gè)類型有沒(méi)有實(shí)現(xiàn)__iadd__這個(gè)方法。總的來(lái)說(shuō),可變序列一般都實(shí)現(xiàn)了__iadd__這個(gè)方法,因此+=是就地加法。而不可變序列沒(méi)有實(shí)現(xiàn)這個(gè)方法,就會(huì)像步驟(2)那樣操作。后者相對(duì)應(yīng)的是__imul__.
例子:
l = [1, 2, 3] print('before id(l):',id(l)) l *=2 print(l) print('after id(l):',id(l)) t = (1, 2, 3) print('before id(t):',id(t)) t *= 2 print('after id(t):',id(t)) # 運(yùn)用增量懲罰后,新的元組被創(chuàng)建結(jié)果如圖:
關(guān)于 +=的謎題
t = (1, 2, [30,40]) t[2] += [50, 60] print(t)
結(jié)果:t[2]被改動(dòng)了,但是也有異常出現(xiàn)。但是我們可以寫(xiě)成t[2].extend([50,60])來(lái)避免這個(gè)異常。
教訓(xùn):
- 不要把可變對(duì)象放在元組里面
- 增量賦值不是一個(gè)原子操。它雖然會(huì)拋出異常,但是還是完成了操作
- 查看python的字節(jié)碼并不難,它對(duì)我們了解代碼背后的運(yùn)行機(jī)制很有幫助。
補(bǔ)充:extend()方法和+有什么區(qū)別呢?
a = [1,2,3] b = [4,5,6] c = a+bd = [1,2,3] e = [4,5,6] d.extend(e)結(jié)果如圖:
結(jié)論:
結(jié)果是一樣的,但是+號(hào)生成的是一個(gè)新的對(duì)象,而extend則是在原地的修改對(duì)象。
extend()的運(yùn)算效率比+更高。但是, d.extend(e) 的返回結(jié)果是None,而不是合并后的序列。d序列是合并后的序列。
c返回的是新的序列。
2.7 list.sort方法和內(nèi)置函數(shù)sorted(排序)
list.sort方法會(huì)就地排序列表,這也是這個(gè)方法返回None的原因,按照python的慣例:如果一個(gè)函數(shù)或者方法對(duì)對(duì)象進(jìn)行的是就地改動(dòng),那它就應(yīng)該返回None.
與list.sort相反的是sorted,它會(huì)新建一個(gè)列表作為返回值。這個(gè)方法可以接受人和形式的可迭代對(duì)象作為參數(shù),甚至包括不可變序列或者生成器,但是它總是返回一個(gè)列表。
不管list.sort或者sorted函數(shù),都有兩個(gè)參數(shù),reverse和key
- reverse:默認(rèn)為False,就是升序排列,True為降序排列
- key:對(duì)一些字符串進(jìn)行排序的時(shí)候,key=str.lower來(lái)實(shí)現(xiàn)忽略大小寫(xiě)的排序;key=len來(lái)顯示根據(jù)字符串長(zhǎng)度來(lái)排序。
例子:
fruits = ['grape', 'raspberry', 'apple', 'banana'] print("未排序:", fruits) print(sorted(fruits)) print("sorted:", fruits) print(sorted(fruits,reverse=True)) print(sorted(fruits,key=len)) print(sorted(fruits,key=len,reverse=True)) print(fruits) fruits.sort() print(fruits)結(jié)果如下:
可以發(fā)現(xiàn),直到執(zhí)行了fruits.sort方法,fruits本身才發(fā)生了變化。
排好序的序列可以用來(lái)進(jìn)行快速搜索,而標(biāo)準(zhǔn)庫(kù)的bisect模塊給我們提供了二分查找算法。
2.8 用bisect來(lái)管理已排序的序列
bisect模塊包含類 兩個(gè)主要函數(shù),bisect和insert,兩個(gè)函數(shù)都利用二分查找算法在有序序列中查找或者插入元素。
在有序序列中用bisect查找某個(gè)元素的插入位置。
例子1:
例子2:根據(jù)分?jǐn)?shù)找到它對(duì)應(yīng)的成績(jī)
import bisect def grade(score,breakpoint = [60,70,80,90],grades='FDCBA'):i = bisect.bisect(breakpoint,score) # 返回i,匹配gradesreturn grades[i] t = [grade(score) for score in [33,99,77,70,89,91,10]] print(t)輸出:
['F', 'A', 'C', 'C', 'B', 'A', 'F']2.8.2用bisect.insort插入元素
insort(seq,item) 把變量item插入到序列seq中,并能保持seq的升序順序。
import bisect import random SIZE = 7 random.seed(1729) my_list = [] for i in range(SIZE):new_item = random.randrange(SIZE*2)bisect.insort(my_list, new_item)print('%2d ->' % new_item, my_list)結(jié)果如圖:
- 補(bǔ)充: %和format的區(qū)別
參考:https://www.cnblogs.com/zhaopanpan/p/8875765.html (%和format的區(qū)別)
2.9 當(dāng)列表不是首選時(shí)
2.9.1 數(shù)組
2.9.2內(nèi)存視圖
2.9.3 NumPy和SciPy
科學(xué)計(jì)算有關(guān)的算法
窺探NumPy二維數(shù)組的基本操作
import numpy a = numpy.arange(12) print(a) print(type(a)) print(a.shape)#查看維度 a.shape = 3, 4 #變成二維的 print(a) print(a[2]) print(a[2, 1]) print(a[:, 1]) t = a.transpose() #行列交換,得到**新的數(shù)組** print(t)結(jié)果如下:
可以發(fā)現(xiàn)t是一個(gè)新的數(shù)組。
2.9.4 雙向隊(duì)列和其他的形式的隊(duì)列
補(bǔ)充:markdown生成目錄方式,在開(kāi)頭輸出[toc]
總結(jié)
以上是生活随笔為你收集整理的python (第二章)数据结构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Git:(1)简介
- 下一篇: 第四十期:九个对Web开发者最有用的Py