四、序列類型操作符
1、索引和切片操作符 ( [],[:],[::] )
序列類型的元素被順序放置,這種方式允許通過指定下標的方式來獲得某一個數據元素, 或者通過指定下標范圍來獲得一組序列的元素,這種訪問序列單個元素的方式叫做索引,獲取子序列的方式叫做切片。
序列支持的索引操作:
sequence[index]
<meta charset="utf-8">
sequence
是序列的名字,index
是想要訪問的元素對應的偏移量。偏移量可以是正值,范圍從 0 到偏移最大值(比序列長度少1),可以使用內建函數 len()
返回序列的元素個數, 所以:0 <= index <= len(sequece) - 1 。另外,也可以使用負索引,范圍是 -1 到序列的負長度:-len(sequence),所以:-len(sequence) <= index <= -1。
正負索引的區別在于正索引以序列的開始為起點,負索引以序列的結束為起點。從技術上講,一個負偏移與這個字符串的常度相加后得到這個字符串的正的偏移量。我們可以理解為當Python去所以一個負偏移量的時候,會將其負偏移量加上序列的長度后得到對應的正偏移量,再去索引。
序列支持的切片操作:
sequence[starting_index:ending_index:step]
當使用一對以冒號分隔的偏移來索引序列類型對象時,我們可以得到從起始索引(starting_index)到結束索引(ending_index)(不包括結束索引對應的元素)之間的所有元素。起始索引和結束索引都是可選的, 如果沒有提供或者用 None 作為索引值,其實索引和結束索引會默認為0和分片對象的長度。
對序列對象進行分片操作,會返回一個新的同樣類型的對象。索引和分片的賦值操作都是原處修改,對于不可變對象,會引發錯誤異常。他們會對可變對象直接進行修改,而不是生成一個新的對象作為結果。
分片賦值時,插入元素的個數不需要與刪除的數目相匹配。實際上,分片賦值是一次性替換整個片段或“欄”,因為賦值的序列長度不一定要與被賦值的分片的長度相匹配,所以分片賦值能夠用來替換(覆蓋)、增長(插入)、縮短(刪除)主列表。
2、成員關系操作符 (in, not in)
成員關系操作符使用來判斷一個元素是否屬于一個序列的。比如對字符串類型來說,就是判斷一個字符是否屬于這個字符串,對和元組類型來說,就代表了一個對象是否屬于該元組。in/not in 操作符的返回值一般來講就是 True/False,滿足成員關系就返回 True,否則返回 False。
obj [not] in sequence
3、連接操作符( + )
這個操作符允許我們把一個序列和另一個相同類型的序列做連接。
sequence1 + sequence2
該表達式的結果是一個包含 sequence1 和 sequence2 的內容的新序列。注意:這種方式看起來似乎實現了把兩個序列內容合并的概念,但是這個操作不是最快或者說最有效的。對字符串來說,這個操作不如把所有的子字符串放到一個列表或可迭代對象中,然后調用一個 join() 方法來把所有的內容連接在一起節約內存。類似地,對列表來說,我們推薦讀者用列表類型的 extend() 方法來把兩個或者多個列表對象合并。當你需要簡單地把兩個對象的內容合并, 或者說不能依賴于可變對象的那些沒有返回值(實際上它返回一個 None)的內建方法來完成的時候時,連接操作符還是很方便的一個選擇。
4、重復操作符 ( * )
當你需要需要一個序列的多份拷貝時,重復操作符非常有用。
sequence * copies_int
copies_int 必須是一個整數,像連接操作符一樣,該操作符返回一個新的包含多份原對象拷貝的對象。
五、序列可用的內建函數
在講解序列類型的內建函數之前,有一點需要說明,序列本身就內含了迭代的概念,之所以會這樣,是因為迭代這個概念就是從序列,迭代器,或者其他支持迭代操作的對象中泛化得來的。由于 Python 的 for 循環可以遍歷所有的可迭代類型,在(非純序列對象上)執行 for 循環時就像在一個純序列對象上執行一樣。 而且 Python 的很多原來只支持序列作為參數的內建函數現在也開始支持迭代器或者或類迭代器了。我們把這些類型統稱為"可迭代對象"。
1、類型轉換函數 list(),tuple() 和 str() (repr())
內建函數 list()
,str()
和 tuple()
[圖片上傳中...(13.png-ff9688-1515593009797-0)]
被用做在各種序列類型之間轉換。這些轉換實際上是工廠函數,將對象作為參數,并將其內容(淺)拷貝到新生成的對象中。一旦一個 Python 的對象被建立,我們就不能更改其身份或類型了。如果你把一個列表對象傳給 list() 函數,便會創建這個對象的一個淺拷貝,然后將其插入新的列表中。同樣地,在做連接操作和重復操作時,我們也會這樣處理。
所謂淺拷貝就是只拷貝了對象中元素對象的索引,而不是重新建立了對象中所有的元素對象!如果你想完全的拷貝一個對象(包括遞歸,如果你的對象是一個包含容器的容器)。你需要用到深拷貝。
list() 和 tuple() 函數在列表類型和元組類型的互換時非常有用。 雖然這些函數也適用于 string 類型(因為 string 類型也是序列的一種),但是在 string 類型上應用 tuple()和 list()函數卻得不到我們通常希望的結果。內建函數 str()
和 repr()
可以獲取對象的內容、類型、數值屬性等信息的字符串格式。str() 函數得到的字符串可讀性好, 而 repr()函數得到的字符串通常可以用來重新獲得該對象, 通常情況下 obj == eval(repr(obj)) 這個等式是成立的。這兩個函數接受一個對象做為其參數,返回適當的字符串。
需要再次提醒一下的是, 并不是所有 repr()返回的字符串都能夠用eval()內建函數得到原來的對象。
也就是說 repr() 輸出對 Python 比較友好, 而 str()的輸出對人比較友好。雖然如此,很多情況下這二者的輸出仍然都是完全一樣的。
2、返回對象的長度 len()
內建函數 len() 可以返回序列對象的長度(元素個數)。3、返回最大值和最小值 max() 和 min()
對于 string 類型它們能返回最大或者最小的字符(按照ASCII碼中的字符的先后順序比較)。對于元組和列表來說,當其元素都為字符串或者數字對象時,才可以返回正確結果。對于混合對象,結構越復雜返回的結構準確性就越差。
六、拷貝 Python 對象淺拷貝和深拷貝
對象賦值實際上是簡單的對象引用。也就是說當你創建一個對象,然后把它賦給另一個變量的時候,Python 并沒有拷貝這個對象,而是拷貝了這個對象的引用給變量。原因是我們僅僅做了一個淺拷貝。對一個對象進行淺拷貝其實是新創建了一個類型跟原對象一樣,其內容是原來對象內容的拷貝(其實都是原對象中元素的引用),換句話說,這個拷貝的對象本身是新的,但是它的內容不是。序列類型對象的淺拷貝是默認類型拷貝,并可以以下幾種方式實施:(1)完全切片操作[:],(2)利用工廠函數,比如 list(),dict()等,(3)使用 copy 模塊的 copy() 函數。
你的下一個問題可能是:當妻子的名字被賦值,為什么丈夫的名字沒有受到影響?難道它們的名字現在不應該都是'jane'了嗎?為什么名字沒有變成一樣的呢?怎么會是這樣呢?這是因為在這兩個列表的兩個對象中,第一個對象是不可變的(是個字符串類型),而第二個是可變的(一個列表)。正因為如此,當進行淺拷貝時,字符串對象和列表對象的引用都被進行拷貝到了新的列表中,正如上圖我們看到的,剛拷貝完,person、hubby、wifey三個對象的id不同,但是其內部元素的id都是相同的,正是因為他們內部的元素都指向了相同的對象。而當我們對hubby和wifey第一個元素進行賦值時,由于字符串是不可改變對象,所以他們的第一個元素都指向了各自新創建的字符串對象。由于列表是可變對象。所以hubby對第二個元素列表中的數字進行了修改之后,由于wifey的第二個元素也是指向的同一個列表對象,所以我們看wifey中的錢也發生了變化。
假設我們要給這對夫妻創建一個聯合賬戶,那這是一個非常棒的方案,但是,如果需要的是兩個分離賬戶,就需要作些改動了。要得到一個完全拷貝或者說深拷貝--創建一個新的容器對象,包含原有對象元素以及所有嵌套元素全新的拷貝--需要 copy.deepcopy()函數。我們使用深拷貝來重寫整個例子。注意: 上面示例中你可能認為深拷貝的列表中的第一個元素和原列表的id值不應該一樣。首先肯定的是你的理解是沒有問題的,只是Python為了優化效率,在解釋器內提前初始化了一些常用的字符串,包括 'name',所以person、hubby、wifey的第一個元素都指向了Python解釋器提前初始化的'name'對象。如果是更復雜的字符串,其id值就會不一樣了。
注意: 第一,非容器類型(比如數字,字符串和其他"原子"類型的對象,像代碼,類型和 xrange 對象等)沒有被拷貝一說,淺拷貝是用完全切片操作來完成的。第二,如果元組變量只包含原子類型對象,對它的深拷貝將不會進行。如果我們把賬戶信息改成元組類型,那么即便按我們的要求使用深拷貝操作也只能得到一個淺拷貝。
《Python基礎手冊》系列:
Python基礎手冊 1 —— Python語言介紹
Python基礎手冊 2 —— Python 環境搭建(Linux)
Python基礎手冊 3 —— Python解釋器
Python基礎手冊 4 —— 文本結構
Python基礎手冊 5 —— 標識符和關鍵字
Python基礎手冊 6 —— 操作符
Python基礎手冊 7 —— 內建函數
Python基礎手冊 8 —— Python對象
Python基礎手冊 9 —— 數字類型
Python基礎手冊10 —— 序列(字符串)
Python基礎手冊11 —— 序列(元組&列表)
Python基礎手冊12 —— 序列(類型操作)
Python基礎手冊13 —— 映射(字典)
Python基礎手冊14 —— 集合
Python基礎手冊15 —— 解析
Python基礎手冊16 —— 文件
Python基礎手冊17 —— 簡單語句
Python基礎手冊18 —— 復合語句(流程控制語句)
Python基礎手冊19 —— 迭代器
Python基礎手冊20 —— 生成器
Python基礎手冊21 —— 函數的定義
Python基礎手冊22 —— 函數的參數
Python基礎手冊23 —— 函數的調用
Python基礎手冊24 —— 函數中變量的作用域
Python基礎手冊25 —— 裝飾器
Python基礎手冊26 —— 錯誤 & 異常
Python基礎手冊27 —— 模塊
Python基礎手冊28 —— 模塊的高級概念
Python基礎手冊29 —— 包