在python中有三種内建的資料結構——清單、元組和字典。
<code>list</code>是處理一組有序項目的資料結構,即你可以在一個清單中存儲一個 序列 的項目。假想你有一個購物清單,上面記載着你要買的東西,你就容易了解清單了。隻不過在你的購物表上,可能每樣東西都獨自占有一行,而在python中,你在每個項目之間用逗号分割。
清單中的項目應該包括在方括号中,這樣python就知道你是在指明一個清單。一旦你建立了一個清單,你可以添加、删除或是搜尋清單中的項目。由于你可以增加或删除項目,我們說清單是可變的 資料類型,即這種類型是可以被改變的。
對象與類的快速入門
清單是使用對象和類的一個例子。當你使用變量<code>i</code>并給它指派的時候,比如賦整數<code>5</code>,你可以認為你建立了一個類(類型)<code>int</code>的對象(執行個體)<code>i</code>。事實上,你可以看一下<code>help(int)</code>以更好地了解這一點。
類也有方法,即僅僅為類而定義地函數。僅僅在你有一個該類的對象的時候,你才可以使用這些功能。例如,python為<code>list</code>類提供了<code>append</code>方法,這個方法讓你在清單尾添加一個項目。例如<code>mylist.append('an item')</code>清單<code>mylist</code>中增加那個字元串。注意,使用點号來使用對象的方法。
一個類也有域,它是僅僅為類而定義的變量。僅僅在你有一個該類的對象的時候,你才可以使用這些變量/名稱。類也通過點号使用,例如<code>mylist.field</code>。
使用清單
變量<code>shoplist</code>是某人的購物清單。在<code>shoplist</code>中,我們隻存儲購買的東西的名字字元串,但是記住,你可以在清單中添加任何種類的對象 包括數甚至其他清單。
注意,我們在<code>print</code>語句的結尾使用了一個 逗号 來消除每個<code>print</code>語句自動列印的換行符。這樣做有點難看,不過确實簡單有效。
接下來,我們使用<code>append</code>方法在清單中添加了一個項目,就如前面已經讨論過的一樣。然後我們通過列印清單的内容來檢驗這個項目是否确實被添加進清單了。列印清單隻需簡單地把清單傳遞給<code>print</code>語句,我們可以得到一個整潔的輸出。
再接下來,我們使用清單的<code>sort</code>方法來對清單排序。需要了解的是,這個方法影響清單本身,而不是傳回一個修改後的清單——這與字元串工作的方法不同。這就是我們所說的清單是可變的 而字元串是不可變的 。
最後,但我們完成了在市場購買一樣東西的時候,我們想要把它從清單中删除。我們使用<code>del</code>語句來完成這個工作。這裡,我們指出我們想要删除清單中的哪個項目,而<code>del</code>語句為我們從清單中删除它。我們指明我們想要删除清單中的第一個元素,是以我們使用<code>del shoplist[0]</code>(記住,python從0開始計數)。
如果你想要知道清單對象定義的所有方法,可以通過<code>help(list)</code>獲得完整的知識。
通過清單綜合,可以從一個已有的清單導出一個新的清單。例如,你有一個數的清單,而你想要得到一個對應的清單,使其中所有大于2的數都是原來的2倍。對于這種應用,清單綜合是最理想的方法。
這裡我們為滿足條件(<code>if i > 2</code>)的數指定了一個操作(<code>2*i</code>),進而導出一個新的清單。注意原來的清單并沒有發生變化。在很多時候,我們都是使用循環來處理清單中的每一個元素,而使用清單綜合可以用一種更加精确、簡潔、清楚的方法完成相同的工作。
元組和清單十分類似,隻不過元組和字元串一樣是 不可變的 即你不能修改元組。元組通過圓括号中用逗号分割的項目定義。元組通常用在使語句或使用者定義的函數能夠安全地采用一組值的時候,即被使用的元組的值不會改變。
使用元組
變量zoo是一個元組,我們看到len函數可以用來擷取元組的長度。這也表明元組也是一個序列。
由于老動物園關閉了,我們把動物轉移到新動物園。是以,new_zoo元組包含了一些已經在那裡的動物和從老動物園帶過來的動物。回到話題,注意元組之内的元組不會失去它的身份。
我們可以通過一對方括号來指明某個項目的位置進而來通路元組中的項目,就像我們對清單的用法一樣。這被稱作 索引 運算符。我們使用new_zoo[2]來通路new_zoo中的第三個項目。我們使用new_zoo[2][2]來通路new_zoo元組的第三個項目的第三個項目。
含有0個或1個項目的元組。
一個空的元組由一對空的圓括号組成,如myempty = ()。然而,含有單個元素的元組就不那麼簡單了。你必須在第一個(唯一一個)項目後跟一個逗号,這樣python才能區分元組和表達式中一個帶圓括号的對象。即如果你想要的是一個包含項目2的元組的時候,你應該指明singleton = (2 , )。
給perl程式員的注釋
清單之中的清單不會失去它的身份,即清單不會像perl中那樣被打散。同樣元組中的元組,或清單中的元組,或元組中的清單等等都是如此。隻要是python,它們就隻是使用另一個對象存儲的對象。
元組與列印語句
元組最通常的用法是用在列印語句中,下面是一個例子:
<code>print</code>語句可以使用跟着<code>%</code>符号的項目元組的字元串。這些字元串具備定制的功能。定制讓輸出滿足某種特定的格式。定制可以是<code>%s</code>表示字元串或<code>%d</code>表示整數。元組必須按照相同的順序來對應這些定制。
觀察我們使用的第一個元組,我們首先使用<code>%s</code>,這對應變量<code>name</code>,它是元組中的第一個項目。而第二個定制是<code>%d</code>,它對應元組的第二個項目<code>age</code>。
python在這裡所做的是把元組中的每個項目轉換成字元串并且用字元串的值替換定制的位置。是以<code>%s</code>被替換為變量<code>name</code>的值,依此類推。
<code>print</code>的這個用法使得編寫輸出變得極其簡單,它避免了許多字元串操作。它也避免了我們一直以來使用的逗号。
在大多數時候,你可以隻使用<code>%s</code>定制,而讓python來提你處理剩餘的事情。這種方法對數同樣奏效。然而,你可能希望使用正确的定制,進而可以避免多一層的檢驗程式是否正确。
在第二個<code>print</code>語句中,我們使用了一個定制,後面跟着<code>%</code>符号後的單個項目——沒有圓括号。這隻在字元串中隻有一個定制的時候有效。
當要使函數接收元組或字典形式的參數的時候,有一種特殊的方法,它分别使用<code>*</code>和<code>**</code>字首。這種方法在函數需要擷取可變數量的參數的時候特别有用。
由于在<code>args</code>變量前有<code>*</code>字首,所有多餘的函數參數都會作為一個元組存儲在<code>args</code>中。如果使用的是<code>**</code>字首,多餘的參數則會被認為是一個字典的鍵/值對。
字典類似于你通過聯系人名字查找位址和聯系人詳細情況的位址簿,即,我們把鍵(名字)和值(詳細情況)聯系在一起。注意,鍵必須是唯一的,就像如果有兩個人恰巧同名的話,你無法找到正确的資訊。
注意,你隻能使用不可變的對象(比如字元串)來作為字典的鍵,但是你可以使用不可變或可變的對象作為字典的值。基本說來就是,你應該隻使用簡單的對象作為鍵。
鍵值對在字典中以這樣的方式标記:<code>d = {key1 : value1, key2 : value2 }</code>。注意它們的鍵/值對用冒号分割,而各個對用逗号分割,所有這些都包括在花括号中。
記住字典中的鍵/值對是沒有順序的。如果你想要一個特定的順序,那麼你應該在使用前自己對它們排序。
字典是<code>dict</code>類的執行個體/對象。
我們使用已經介紹過的标記建立了字典<code>ab</code>。然後我們使用在清單和元組章節中已經讨論過的索引操作符來指定鍵,進而使用鍵/值對。我們可以看到字典的文法同樣十分簡單。
我們可以使用索引操作符來尋址一個鍵并為它指派,這樣就增加了一個新的鍵/值對,就像在上面的例子中我們對guido所做的一樣。
我們可以使用我們的老朋友——<code>del</code>語句來删除鍵/值對。我們隻需要指明字典和用索引操作符指明要删除的鍵,然後把它們傳遞給<code>del</code>語句就可以了。執行這個操作的時候,我們無需知道那個鍵所對應的值。
接下來,我們使用字典的<code>items</code>方法,來使用字典中的每個鍵/值對。這會傳回一個元組的清單,其中每個元組都包含一對項目——鍵與對應的值。我們抓取這個對,然後分别賦給<code>for..in</code>循環中的變量<code>name</code>和<code>address</code>然後在for-塊中列印這些值。
我們可以使用<code>in</code>操作符來檢驗一個鍵/值對是否存在,或者使用<code>dict</code>類的<code>has_key</code>方法。你可以使用<code>help(dict)</code>來檢視<code>dict</code>類的完整方法清單。
關鍵字參數與字典。如果換一個角度看待你在函數中使用的關鍵字參數的話,你已經使用了字典了!隻需想一下——你在函數定義的參數清單中使用的鍵/值對。當你在函數中使用變量的時候,它隻不過是使用一個字典的鍵(這在編譯器設計的術語中被稱作符号表 )。
清單、元組和字元串都是序列,但是序列是什麼,它們為什麼如此特别呢?序列的兩個主要特點是索引操作符和切片操作符。索引操作符讓我們可以從序列中抓取一個特定項目。切片操作符讓我們能夠擷取序列的一個切片,即一部分序列。
使用序列
首先,我們來學習如何使用索引來取得序列中的單個項目。這也被稱作是下标操作。每當你用方括号中的一個數來指定一個序列的時候,python會為你抓取序列中對應位置的項目。記住,python從0開始計數。是以,<code>shoplist[0]</code>抓取第一個項目,<code>shoplist[3]</code>抓取<code>shoplist</code>序列中的第四個元素。
索引同樣可以是負數,在那樣的情況下,位置是從序列尾開始計算的。是以,<code>shoplist[-1]</code>表示序列的最後一個元素而<code>shoplist[-2]</code>抓取序列的倒數第二個項目。
切片操作符是序列名後跟一個方括号,方括号中有一對可選的數字,并用冒号分割。注意這與你使用的索引操作符十分相似。記住數是可選的,而冒号是必須的。
切片操作符中的第一個數(冒号之前)表示切片開始的位置,第二個數(冒号之後)表示切片到哪裡結束。如果不指定第一個數,python就從序列首開始。如果沒有指定第二個數,則python會停止在序列尾。注意,傳回的序列從開始位置開始 ,剛好在結束 位置之前結束。即開始位置是包含在序列切片中的,而結束位置被排斥在切片外。
這樣,<code>shoplist[1:3]</code>傳回從位置1開始,包括位置2,但是停止在位置3的一個序列切片,是以傳回一個含有兩個項目的切片。類似地,<code>shoplist[:]</code>傳回整個序列的拷貝。
你可以用負數做切片。負數用在從序列尾開始計算的位置。例如,<code>shoplist[:-1]</code>會傳回除了最後一個項目外包含所有項目的序列切片。
使用python解釋器互動地嘗試不同切片指定組合,即在提示符下你能夠馬上看到結果。序列的神奇之處在于你可以用相同的方法通路元組、清單和字元串。
當你建立一個對象并給它賦一個變量的時候,這個變量僅僅 參考 那個對象,而不是表示這個對象本身!也就是說,變量名指向你計算機中存儲那個對象的記憶體。這被稱作名稱到對象的綁定。
一般說來,你不需要擔心這個,隻是在參考上有些細微的效果需要你注意。這會通過下面這個例子加以說明。
大多數解釋已經在程式的注釋中了。你需要記住的隻是如果你想要複制一個清單或者類似的序列或者其他複雜的對象(不是如整數那樣的簡單 對象 ),那麼你必須使用切片操作符來取得拷貝。如果你隻是想要使用另一個變量名,兩個名稱都參考 同一個對象,那麼如果你不小心的話,可能會引來各種麻煩。
記住清單的指派語句不建立拷貝。你得使用切片操作符來建立序列的拷貝。
我們已經在前面詳細讨論了字元串。我們還需要知道什麼呢?那麼,你是否知道字元串也是對象,同樣具有方法。這些方法可以完成包括檢驗一部分字元串和去除空格在内的各種工作。
你在程式中使用的字元串都是<code>str</code>類的對象。這個類的一些有用的方法會在下面這個例子中說明。如果要了解這些方法的完整清單,請參見<code>help(str)</code>。
這裡,我們看到使用了許多字元串方法。<code>startwith</code>方法是用來測試字元串是否以給定字元串開始。<code>in</code>操作符用來檢驗一個給定字元串是否為另一個字元串的一部分。
<code>find</code>方法用來找出給定字元串在另一個字元串中的位置,或者傳回-1以表示找不到子字元串。<code>str</code>類也有以一個作為分隔符的字元串<code>join</code>序列的項目的整潔的方法,它傳回一個生成的大字元串。