简明python教程 --C++程序员的视角(四):容器类型(字符串、元组、列表、字典)和参考
數據結構簡介
Python定義的類型(或對象)層次結構在概念上可以劃分為四種類別:簡單類型、容器類型、代碼類型?和內部類型。
可以將?PyObject?類之下的所有 Python 類劃分為 Python 運行時解釋器可以使用的四個主要類別:
- 簡單類型?—— 基本構建塊,如?int?和?float。
- 容器類型—— 保存其他對象。
- 代碼類型—— 封裝 Python 程序的元素。
- 內部類型?—— 程序執行期間使用的類型。
?
內置的簡單類型
Python 有五個內置的簡單類型:bool、int、long、float?和?complex。在 Python 中,簡單數據類型并不是原始數據類型,而是完善的對象,它們有自已的方法和類。另外,這些簡單的內置類型是不可改變的,這意味著:創建對象之后,您無法更改對象的值。如果需要新值,則必須創建新的對象。通過 Python?id?函數,可以查看基本?PyObject?標識的變更方式:
清單 3. 使用 Python?id?函數
| >>> i = 100 >>> id(i) 8403284 >>> i = 101 >>> id(i) 8403296 |
此方法看似容易丟失對象,會導致內存泄漏。但是,Python 像 C# 和 Java 一樣,使用了垃圾回收功能,以釋放用于保存不再引用的對象的內存,如上例中用于保存 100 的整數對象。
?
容器類型
當您的程序需要一次處理多個對象時,就可以利用 Python 容器類:
- tuple
- string
- unicode
- frozenset
- list
- set
- dictionary
有序性:
這些容器類型提供了兩種功能。前六個類型是有序的(序列),最后一個類型?dictionary?則是一個映射。
可變性:
前四種容器類型(tuple,string,unicode,frozenset)的順序是不可變的,這意味著在您創建了這些容器類型之一后,所存儲的數據就不可更改。如果出于某種原因需要更改數據,則需要創建一個新容器來保存新的數據。
后三種容器類型(list、set、dictionary)都是可變容器,因此,它們可以根據需要更改保存的任何數據(但在 dictionary 中所使用的密鑰是不可變的,就像您房間的鑰匙)。
雖然可變容器非常靈活,但它們的動態特性會對性能造成影響。例如,tuple?類型,盡管它是不可變的,靈活性較差,但在同一環境中使用時,它們通常比?list?類型快得多。
?
之前已經介紹了字符串,下小節我們將會學習如何使用元組、列表和字典,以及它們如何使編程變得簡單。?
元組
- 元組和列表十分類似,只不過元組和字符串一樣是?不可變的?即你不能修改元組。
- 元組通過圓括號中用逗號分割的項目定義。元組通常用在使語句或用戶定義的函數能夠安全地采用一組值的時候,即被使用的元組的值不會改變。
- 含有0個或1個項目的元組。一個空的元組由一對空的圓括號組成,如myempty = ()。然而,含有單個元素的元組就不那么簡單了。你必須在第一個(唯一一個)項目后跟一個逗號,這樣Python才能區分元組和表達式中一個帶圓括號的對象。即如果你想要的是一個包含項目2的元組的時候,你應該指明singleton = (2 , )。
- tuple?實際上是一個異構容器,創建可以擁有各種類型數據項(其中包括另一?tuple)的?tuple?。
變量zoo是一個元組,我們看到len函數可以用來獲取元組的長度。這也表明元組也是一個序列。
?
>>> t = (0,1,2,3,4,5,6,7,8,9) >>> type(t) <type 'tuple'> >>> t (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) >>> tt = 0,1,2,3,4,5,6,7,8,9 >>> type(tt) <type 'tuple'> >>> tt (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) >>> tc=tuple((0,1,2,3,4,5,6,7,8,9)) >>> tc (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) >>> et = () # An empty tuple >>> et () >>> st = (1,) # A single item tuple >>> st (1,) >>> t = (0,1,"two",3.0,"four",(5,6)) >>> tn = t[1:3] + t[3:6] # Add two tuples >>> tn (1, 'two', 3.0, 'four', (5, 6)) >>> tn = t[1:3] + t[3:6] + (7,8,9,"ten") >>> tn (1, 'two', 3.0, 'four', (5, 6), 7, 8, 9, 'ten') >>> t2 = tn[:] # Duplicate an entire tuple, a full slice >>> t2 (1, 'two', 3.0, 'four', (5, 6), 7, 8, 9, 'ten') >>> len(tn) # Find out how many items are in the tuple 9 >>> tn[4][0] # Access a nested tuple 5
- 您還可以從稱為打包?的過程的一組現有變量中創建一個tuple。
- 反之亦然,其中,tuple?中的值被指派給變量。這之后的過程稱為解包,它是用于許多情形的功能十分強大的技術,其中包括希望從一個函數中返回多個值。在解包?tuple?時,僅有的問題是必須為tuple?中的每個數據項提供一個變量。
許多其他容器類型具有類似的功能,其中包括分段以及打包或解包,了解?tuple?的工作原理意味著您已經開始完全理解 Python 中的其他容器類型。
?
元組與打印語句
print語句可以使用跟著%符號的項目元組的字符串。這些字符串具備定制的功能。定制讓輸出滿足某種特定的格式。Python在這里所做的是把元組中的每個項目轉換成字符串并且用字符串的值替換定制的位置。print的這個用法使得編寫輸出變得極其簡單,它避免了許多字符串操作。它也避免了我們一直以來使用的逗號。
在大多數時候,你可以只使用%s定制,而讓Python來提你處理剩余的事情。這種方法對數同樣奏效。然而,你可能希望使用正確的定制,從而可以避免多一層的檢驗程序是否正確。
在第二個print語句中,我們使用了一個定制,后面跟著%符號后的單個項目——沒有圓括號。這只在字符串中只有一個定制的時候有效。
?
列表
- list是處理一組有序項目的數據結構,即你可以在一個列表中存儲一個?序列?的項目。你可以在列表中添加?任何種類的對象?包括數甚至其他列表。在Python中,你在每個項目之間用逗號分割。
- 列表中的項目應該包括在方括號中,這樣Python就知道你是在指明一個列表。
- 一旦你創建了一個列表,你可以添加、刪除或是搜索列表中的項目。由于你可以增加或刪除項目,我們說列表是?可變的?數據類型,即這種類型是可以被改變的。
對象與類的快速入門
- 列表是使用對象和類的一個例子。當你使用變量i并給它賦值的時候,比如賦整數5,你可以認為你創建了一個類(類型)int的對象(實例)i。事實上,你可以看一下help(int)以更好地理解這一點。
- 類也有方法,即僅僅為類而定義的函數。僅僅在你有一個該類的對象的時候,你才可以使用這些功能。例如,Python為list類提供了append方法,這個方法讓你在列表尾添加一個項目。例如mylist.append('an item')列表mylist中增加那個字符串。注意,使用點號來使用對象的方法。
- 一個類也有域,它是僅僅為類而定義的變量。僅僅在你有一個該類的對象的時候,你才可以使用這些變量/名稱。類也通過點號使用,例如mylist.field。
使用列表
我們也使用了for..in循環在列表中各項目間遞歸。從現在開始,你一定已經意識到列表也是一個序列。序列的特性會在后面的章節中討論。
注意,我們在print語句的結尾使用了一個?逗號?來消除每個print語句自動打印的換行符。這樣做有點難看,不過確實簡單有效。
接下來,我們使用append方法在列表中添加了一個項目。再接下來,我們使用列表的sort方法來對列表排序。需要理解的是,這個方法影響列表本身,而不是返回一個修改后的列表——這與字符串工作的方法不同。這就是我們所說的列表是?可變的?而字符串是?不可變的。
最后,我們指出我們想要刪除列表中的哪個項目,而del語句為我們從列表中刪除它。我們指明我們想要刪除列表中的第一個元素,因此我們使用del shoplist[0](記住,Python從0開始計數)。
創建單個條目的?tuple?還需要在單個條目后面跟一個逗號。這是區分單個條目?tuple?與方法調用的必要條件,這一點將在以后詳細討論。而對于?list,則是不必要的,盡管也允許使用單個逗號。
>>> el = [] # Create an empty list >>> len(el) 0 >>> sl = [1] # Create a single item list >>> len(sl) 1>>> sl = [1,] # Create a single item list, as with a tuple >>> len(sl) 1您不僅能夠將序列直接傳遞給構造函數,還可以將擁有元組或字符串的變量傳遞給?list?構造函數。
>>> l = list((0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) # Create a list from a tuple >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> len(l) 10>>> l = list([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) # Create a list from a list >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> len(l) 10>>> l = list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) # Error: Must pass in a sequence Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: list() takes at most 1 argument (10 given) >>> l = list("0123456789") # Create a list from a string >>> l ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] >>> len(l) 10- 切片?是一個非常有用的概念,其一般形式為?l[start:end:step],其中?start?和?end?分別是開始和結束索引,step?是在切片時要跨過的條目數量。
- 此外,還可以對結束索引使用負值,即從序列的結尾往回計數。
- 另一個有用的功能是以一種很合適的方式處理錯誤(如超過序列的長度)。如前一個例子所示,您還可以選擇忽略切片中使用的三個值中的一個或多個值。例如,我在切片?l[0::2]?中沒有使用結束索引。
?list?和?tuple?之間的主要區別在于?list?是一個可變的序列,
- 這就意味著您不但可以方便地訪問?list?中的條目,而且可以方便地修改它們。
- 但這會引起一個并發癥狀:您只能修改序列中的條目。若要向序列中添加條目(而不僅僅是修改條目),可使用?append?方法
- 修改?list?中的條目相當容易:您可以適當地設置條目的值,甚至設置成另一種不同的類型(當然list和tuple一樣都是異構的),如?string?或另一?list。
- 您還可以使用重復運算符*,以便從小片段中構建更大的列表。
- 刪除條目的第一個方法是使用?del?方法。使用此方法可以刪除一個條目或一個條目范圍。
- 您還可以使用靈活而強大的切片方法從?list?中刪除切片。
使用?list?保持二維 (2-D) 或三維 (3-D) 數組
>>> al = [[0, 1, 2], [3, 4, 5], [6, 7, 8]] >>> al[0][0] # First element in 2D array 0 >>> al[2][2] # Last element in 2D array 8 >>> al[1][2] 5>>> al = [[[0, 1], [2, 3]], [[4, 5], [6, 7]]] >>> al[0][0][1] 1 >>> len(al) # Length of outer dimension 2 >>> len(al[0]) # Length of middle dimension 2 >>> len(al[0][0]) # Length of inner dimension 2可以反轉?list?中的所有條目或排序?list:不過,要記住這些操作的一個重點在于,它們是就地(in place)?操作,這意味著它們會修改調用它們所針對的?list。因此,如果您嘗試創建新列表,并將其設置為對這些方法之一調用所產生的結果,則會得到一個空列表。
>>> l=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> id(l) # This is the object id for our current list 4525432>>> l.reverse() # Reverse the list >>> l [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] >>> id(l) # The id is the same, modified list in place. 4525432>>> l.sort() # Sort the list in numerical order >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> id(l) # Modified the existing list 4525432>>> l.index(5) # Same as l[5] 5 >>> l.count(0) # How many times does '0' occur in the list 1list?除可以用于模擬數組外,還可以用于模擬其他數據結構。例如,append?和?pop?方法對?list?函數的操作要么是先進先出 (FIFO) 數據結構(也稱為隊列),要么是后進先出 (LIFO) 數據結構(也稱為堆棧)。通過允許您將條目設置為從?list?中彈出(刪除并返回),pop?方法支持這些功能。如果彈出?list?的第一項,則是一個隊列;反之,如果彈出?list?的最后一項,則是一個堆棧。
>>> l.pop() # Take off the last item (Stack) 9 >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8] >>> l.pop(5) # Take out the fifth element 5 >>> l [0, 1, 2, 3, 4, 6, 7, 8] >>> l.pop(0) # Take the first item off the list (Queue) 0 >>> l [1, 2, 3, 4, 6, 7, 8]如果你想要知道列表對象定義的所有方法,可以通過help(list)獲得完整的知識。
??
序列
列表、元組和字符串都是序列。序列的神奇之處在于你可以用相同的方法訪問元組、列表和字符串。
序列的兩個主要特點是索引操作符和切片操作符。
- 索引操作符讓我們可以從序列中抓取一個特定項目。
- 切片操作符讓我們能夠獲取序列的一個切片,即一部分序列。
使用索引操作符來取得序列中的單個項目(下標操作)。Python從0開始計數。索引同樣可以是負數,可以想象序列是一個首尾相連的環,0表示序列的首元素)。因此,t[-1]表示序列的最后一個元素。
切片操作符是序列名后跟一個方括號,方括號中有一對可選的數字,并用冒號分割。記住數是可選的,而冒號是必須的。切片操作符中的第一個數(冒號之前)表示切片開始的位置,第二個數(冒號之后)表示切片到哪里結束。如果不指定第一個數,Python就從序列首開始。如果沒有指定第二個數,則Python會停止在序列尾。
注意,返回的序列從開始位置?開始?,剛好在?結束?位置之前結束。即開始位置是包含在序列切片中的,而結束位置被排斥在切片外。切片的工作方式是聲明開始索引、結束索引和一個可選的步驟大小,全部都用分號分隔。因此,t[2:7]?將?tuple?中的第三到第七個數據項分段,而?t[2:7:2]?則對每兩個數據項進行分段,從?tuple?中的第三個數據項開始一直到第七個數據項。
| t =?(0,1,2,3,4,5,6,7,8,9) print?t[2] print?(t[0], t[9], t[-1]) print?t[2:7] print?t[:] print?t[2:7:2] print?t[2::2] print?t[:-1] |
2 (0, 9, 9) (2, 3, 4, 5, 6) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) (2, 4, 6) (2, 4, 6, 8) (0, 1, 2, 3, 4, 5, 6, 7, 8)
?
這樣,t[1:3]返回從位置1開始,包括位置2,但是停止在位置3的一個序列切片,因此返回一個含有兩個項目的切片。類似地,t[:]返回整個序列的拷貝。
你可以用負數做切片。負數用在從序列尾開始計算的位置。例如,t[:-1]會返回除了最后一個項目外包含所有項目的序列切片。
使用Python解釋器交互地嘗試不同切片指定組合,即在提示符下你能夠馬上看到結果。
?
字典
- 字典類似于你通過聯系人名字查找地址和聯系人詳細情況的地址簿,即,我們把鍵(名字)和值(詳細情況)聯系在一起。
- 注意,鍵必須是唯一的,就像如果有兩個人恰巧同名的話,你無法找到正確的信息。
- 注意,你只能使用不可變的對象(比如字符串)來作為字典的鍵,但是你可以不可變或可變的對象作為字典的值。基本說來就是,你應該只使用簡單的對象作為鍵。
- 鍵值對在字典中以這樣的方式標記:d = {key1 : value1, key2 : value2 }。注意它們的鍵/值對用冒號分割,而各個對用逗號分割,所有這些都包括在花括號中。
- 記住字典中的鍵/值對是沒有順序的。如果你想要一個特定的順序,那么你應該在使用前自己對它們排序。
- 字典是dict類的實例/對象。
我們可以使用索引操作符來尋址一個鍵并為它賦值,這樣就增加了一個新的鍵/值對,就像在上面的例子中我們對Guido所做的一樣。
我們可以使用del語句來刪除鍵/值對。我們只需要指明字典和用索引操作符指明要刪除的鍵,然后把它們傳遞給del語句就可以了。執行這個操作的時候,我們無需知道那個鍵所對應的值。
接下來,我們使用字典的items方法,來使用字典中的每個鍵/值對。這會返回一個元組的列表,其中每個元組都包含一對項目——鍵與對應的值。我們抓取這個對,然后分別賦給for..in循環中的變量name和address然后在for-塊中打印這些值。
我們可以使用in操作符來檢驗一個鍵/值對是否存在,或者使用dict類的has_key方法。你可以使用help(dict)來查看dict類的完整方法列表。
?
關鍵字參數與字典?如果換一個角度看待你在函數中使用的關鍵字參數的話,你已經使用了字典了!只需想一下——你在函數定義的參數列表中使用的鍵/值對。當你在函數中使用變量的時候,它只不過是使用一個字典的鍵(這在編譯器設計的術語中被稱作?符號表)。
?
參考
當你創建一個對象并給它賦一個變量的時候,這個變量僅僅?參考?那個對象,而不是表示這個對象本身!也就是說,變量名指向你計算機中存儲那個對象的內存。這被稱作名稱到對象的綁定。
大多數解釋已經在程序的注釋中了。你需要記住的只是
如果你想要復制一個列表或者類似的序列或者其他復雜的對象(不是如整數那樣的簡單?對象),那么你必須使用切片操作符來取得拷貝。
如果你只是想要使用另一個變量名,兩個名稱都?參考?同一個對象,那么如果你不小心的話,可能會引來各種麻煩。
from:?http://www.cnblogs.com/wei-li/archive/2012/03/26/2417296.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的简明python教程 --C++程序员的视角(四):容器类型(字符串、元组、列表、字典)和参考的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简明python教程 --C++程序员的
- 下一篇: 简明python教程 --C++程序员的