python 程式設計師會預設序列是支援
+ 和
* 操作的。通常
+ 號兩側的序列由相同型別的資料所構成,在拼接的過程中,兩個被操作的序列都不會被修改,python
會新建乙個包含同樣型別資料的序列來作為拼接的結果。
如果想要把乙個序列複製幾份然後再拼接起來,更快捷的做法是把這個序列乘以乙個整數。+ 和 * 都遵循這個規律,不修改原有的操作物件,而是構建乙個全新的序列。
如果在 a * n
這個語句中,序列
a 裡的元素是對其他可變 物件的引用的話,你就需要格外注意了,因為這個式子的結果可能 會出乎意料。比如,你想用 my_list = * 3
來初始化乙個 由列表組成的列表,但是你得到的列表裡包含的 3
個元素其實是
3 個引用,而且這 3
個引用指向的都是同乙個列表。
演示1建立由列表組成的列表
上述操作等同於(每次迭代中新建了乙個list。作為新的一行新增到board中):
演示2含有3個指向同一物件的引用的列表是毫無用處的
上述錯誤示範等同於(追加同乙個物件3次到board列表):
2.1 +=和*=背後的故事
增量賦值運算子 +=
和 *= 的表現取決於它們的第乙個操作物件。+= 背後的特殊方法是 __iadd__ (用於「就地加法」)。但是如果乙個類沒有實現這個方法的話,python 會退一步呼叫 __add__ 。如:在a += b的執行過程中,如果 a
實現了
__iadd__
方法,就會呼叫這個方法。同時對可變序列來說,a
會就地改動,就像呼叫了 a.extend(b)
一樣。但是如果
a 沒有實現
__iadd__
的話,a += b 這個表示式的效果就變得跟
a = a + b
一樣了:首先計算
a + b,得到乙個新的物件,然後賦值給
a。也就是說,在這個表示式中,變數名會不會被關聯到新的物件,完全取決於這個型別有沒有實現 __iadd__ 這個方法。
總體來講,可變序列一般都實現了 __iadd__
方法,因此
+= 是就地加 法。而不可變序列根本就不支援這個操作,對這個方法的實現也就無從 談起。 上面所說的這些關於 +=
的概念也適用於
*=,不同的是,後者相對應的 是 __imul__。
演示3*=在可變和不可變序列上的對比
對不可變序列進行重複拼接操作的話,效率會很低,因為每次都有乙個新物件,而直譯器需要把原來物件中的元素先複製到新的物件裡,然後再追加新的元素。
str 是乙個例外,因為對字串做 +=
實在是太普遍了,所以
cpython
對它做了優化。為
str 初始化記憶體的時候,程式會為它留出額外的可擴充套件空間,因此進行增量操作的時候,並不會涉及複製原有字串到新位置這類操作。
2.2 乙個關於+=的謎題
上述**中,因為 tuple
不支援對它的元素賦值,所以會丟擲
typeerror 異常。但與此同時元組卻被改變了:t= (1, 2, [30, 40, 50, 60])。這是非常罕見的邊界情況,因此我們需要注意以下3點:
list.sort 方法會就地排序列表,也就是說不會把原列表複製乙份。這也是這個方法的返回值是 none 的原因。在這種情況下返回
none
其實是
python
的乙個慣例:如果乙個函式或者方法對物件進行的是就地改動,那它就應該返回 none
,好讓呼叫者知道傳入的引數發生了變動,而且並未產生新的物件。例如,random.shuffle 函式也遵守了這個慣例。(注:用返回 none 來表示就地改動這個慣例有個弊端,那就是呼叫者無法將其串聯起來。)
與 list.sort 相反的是內建函式 sorted
,它會新建乙個列表作為返回值。這個方法可以接受任何形式的可迭代物件作為引數,甚至包括不可
變序列或生成器。而不管 sorted
接受的是怎樣的引數,它最後都會返回乙個列表。
不管是 list.sort 方法還是
sorted
函式,都有兩個可選的關鍵字引數:
演示4list.sort()和sorted()的用法
已排序的序列可以用來進行快速搜尋,而標準庫的
bisect
模組給我們提供了二分查詢演算法。下一節會詳細講這個函式,順便還會看看bisect.insort 如何讓已排序的序列保持有序。
全域性變數 陣列 第二章 序列構成陣列
python 風格 序列的泛型操作,內建元組和對映型別,用縮進來架構的原始碼,無需變數宣告的強型別等.python 從 abc 語言繼承了用統一風格處理序列資料.資料結構都共用同一套操作 迭代,切片,排序,和拼接.容器序列 list,tuple,collections.deque 等能存放不同型別的...
第二章序列
序列是一種最基本的資料結構,資料結構是通過某種方式把很多資料元素組合在一起的集合 資料元素可以使數字,可以是字元,甚至可以是一些資料結構 內建序列 最重要的是列表和元組 字串 unicode字串 buffer物件 xrange物件 例 edward edward gimby 42 john john...
第二章 第三章
列舉和 define巨集的區別 define巨集常量是在預編譯階段進行簡單替換,列舉常量則是在編譯的時候確定其值。一般在編譯器裡,可以除錯列舉常量,但是不能除錯巨集常量。列舉可以一次定義大量相關的常量,而 define巨集一次只能定義乙個。聯合體 unionperdata 定義了乙個名為perdat...