简明Python教程学习笔记_4_数据结构
在Python中有三種內建的數據結構——列表、元組和字典。
列表
list是處理一組有序項目的數據結構,即你可以在一個列表中存儲一個 序列 的項目。假想你有一個購物列表,上面記載著你要買的東西,你就容易理解列表了。只不過在你的購物表上,可能每樣東西都獨自占有一行,而在Python中,你在每個項目之間用逗號分割。
列表中的項目應該包括在方括號中,這樣Python就知道你是在指明一個列表。一旦你創建了一個列表,你可以添加、刪除或是搜索列表中的項目。由于你可以增加或刪除項目,我們說列表是可變的 數據類型,即這種類型是可以被改變的。
>>>mylist=[1,2,3,a,b,c] >>>type(mylist) >>><type 'list'> >>>dir(list) >>>dir(mylist) >>>help(list)對象與類的快速入門
盡管我一直推遲討論對象和類,但是現在對它們做一點解釋可以使你更好的理解列表。我們會在相應的章節詳細探索這個主題。
列表是使用對象和類的一個例子。當你使用變量i并給它賦值的時候,比如賦整數5,你可以認為你創建了一個類(類型)int的對象(實例)i。事實上,你可以看一下help(int)以更好地理解這一點。
類也有方法,即僅僅為類而定義地函數。僅僅在你有一個該類的對象的時候,你才可以使用這些功能。例如,Python為list類提供了append方法,這個方法讓你在列表尾添加一個項目。例如mylist.append('an item')列表mylist中增加那個字符串。注意,使用點號來使用對象的方法。
一個類也有域,它是僅僅為類而定義的變量。僅僅在你有一個該類的對象的時候,你才可以使用這些變量/名稱。類也通過點號使用,例如mylist.field。
使用列表#!/usr/bin/python # Filename: using_list.py# This is my shopping list shoplist = ['apple', 'mango','carrot','banana']print 'I have', len(shoplist),'items to purchase.' print 'These items are:',# Notice the comma at end of the line for item in shoplist:print item, print '\nI also have to buy rice.' shoplist.append('rice') print 'My shopping list is now', shoplistprint 'I will sort my list now' shoplist.sort() print 'Sorted shopping list is', shoplistprint 'The first item I will buy is', shoplist[0] olditem = shoplist[0] del shoplist[0] print 'I bought the', olditem print 'My shopping list is now', shoplist 輸出 $ python using_list.py I have 4 items to purchase. These items are: apple mango carrot banana I also have to buy rice. My shopping list is now ['apple', 'mango', 'carrot', 'banana', 'rice'] I will sort my list now Sorted shopping list is ['apple', 'banana', 'carrot', 'mango', 'rice'] The first item I will buy is apple I bought the apple My shopping list is now ['banana', 'carrot', 'mango', 'rice']
它如何工作
變量shoplist是某人的購物列表。在shoplist中,我們只存儲購買的東西的名字字符串,但是記住,你可以在列表中添加任何種類的對象 包括數甚至其他列表。
我們也使用了for..in循環在列表中各項目間遞歸。從現在開始,你一定已經意識到列表也是一個序列。序列的特性會在后面的章節中討論。
注意,我們在print語句的結尾使用了一個 逗號 來消除每個print語句自動打印的換行符。這樣做有點難看,不過確實簡單有效。
接下來,我們使用append方法在列表中添加了一個項目,就如前面已經討論過的一樣。然后我們通過打印列表的內容來檢驗這個項目是否確實被添加進列表了。打印列表只需簡單地把列表傳遞給print語句,我們可以得到一個整潔的輸出。
再接下來,我們使用列表的sort方法來對列表排序。需要理解的是,這個方法影響列表本身,而不是返回一個修改后的列表——這與字符串工作的方法不同。這就是我們所說的列表是可變的 而字符串是不可變的 。
最后,但我們完成了在市場購買一樣東西的時候,我們想要把它從列表中刪除。我們使用del語句來完成這個工作。這里,我們指出我們想要刪除列表中的哪個項目,而del語句為我們從列表中刪除它。我們指明我們想要刪除列表中的第一個元素,因此我們使用del shoplist[0](記住,Python從0開始計數)。
如果你想要知道列表對象定義的所有方法,可以通過help(list)獲得完整的知識。
列表綜合
通過列表綜合,可以從一個已有的列表導出一個新的列表。例如,你有一個數的列表,而你想要得到一個對應的列表,使其中所有大于2的數都是原來的2倍。對于這種應用,列表綜合是最理想的方法。
dfadsf
使用列表綜合
#!/usr/bin/python # Filename: list_comprehension.pylistone = [2, 3,4] listtwo = [2*i for i in listone if i>2] print listtwo 輸出 $ python list_comprehension.py [6, 8]它如何工作
這里我們為滿足條件(if i > 2)的數指定了一個操作(2*i),從而導出一個新的列表。注意原來的列表并沒有發生變化。在很多時候,我們都是使用循環來處理列表中的每一個元素,而使用列表綜合可以用一種更加精確、簡潔、清楚的方法完成相同的工作。
元組
元組和列表十分類似,只不過元組和字符串一樣是? 不可變的?即你不能修改元組。元組通過圓括號中用逗號分割的項目定義。元組通常用在使語句或用戶定義的函數能夠安全地采用一組值的時候,即被使用的元組的值不會改變。使用元組
#!/usr/bin/python # Filename: using_tuple.pyzoo = ('wolf', 'elephant','penguin') print 'Number of animals in the zoo is',len(zoo)new_zoo = ('monkey', 'dolphin', zoo) print 'Number of animals in the new zoo is',len(new_zoo) print 'All animals in new zoo are', new_zoo print 'Animals brought from old zoo are', new_zoo[2] print 'Last animal brought from old zoo is', new_zoo[2][2]輸出 $ python using_tuple.py Number of animals in the zoo is 3 Number of animals in the new zoo is 3 All animals in new zoo are ('monkey', 'dolphin', ('wolf', 'elephant', 'penguin')) Animals brought from old zoo are ('wolf', 'elephant', 'penguin') Last animal brought from old zoo is penguin它如何工作
變量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,它們就只是使用另一個對象存儲的對象。
元組與打印語句
元組最通常的用法是用在打印語句中,下面是一個例子:
#!/usr/bin/python # Filename: print_tuple.pyage = 22 name = 'Swaroop'print '%s is %d years old' % (name, age) print 'Why is %s playing with that python?'% name 輸出 $ python print_tuple.py Swaroop is 22 years old Why is Swaroop playing with that python?dictName={'name':'xiaoming','name1':'xiaofang','name2':'huangdi'} print 'dictName[name] ',dictName['name'] print '\n' print 'dictName[name] %s'%dictName['name'] print '\n' print 'dictName[name1] ,dictName[name2] ',dictName['name1'],dictName['name2'] print '\n' print 'dictName[name1] %s ,dictName[name2] %s'%(dictName['name1'],dictName['name2'])它如何工作
print語句可以使用跟著%符號的項目元組的字符串。這些字符串具備定制的功能。定制讓輸出滿足某種特定的格式。定制可以是%s表示字符串或%d表示整數。元組必須按照相同的順序來對應這些定制。
觀察我們使用的第一個元組,我們首先使用%s,這對應變量name,它是元組中的第一個項目。而第二個定制是%d,它對應元組的第二個項目age。
Python在這里所做的是把元組中的每個項目轉換成字符串并且用字符串的值替換定制的位置。因此%s被替換為變量name的值,依此類推。
print的這個用法使得編寫輸出變得極其簡單,它避免了許多字符串操作。它也避免了我們一直以來使用的逗號。
在大多數時候,你可以只使用%s定制,而讓Python來提你處理剩余的事情。這種方法對數同樣奏效。然而,你可能希望使用正確的定制,從而可以避免多一層的檢驗程序是否正確。
在第二個print語句中,我們使用了一個定制,后面跟著%符號后的單個項目——沒有圓括號。這只在字符串中只有一個定制的時候有效。
交換變量值
一般的交換兩個變量的值是用過一個臨時變量、或者 異或、或者相加、或者相乘。但是 Python中有一種賦值機制即多元賦值,采用這種方式賦值時,等號兩邊的對象都是元組并且元組的小括號是可選的。通常形式為
x, y, z = 1, 2, 'a string'等同于 (x, y, z) = (1, 2, 'a string') 。這種賦值類型最經常用到的環境是變量交換,形如: ?x, y = y, x
這種交換方式無需中間變量即可交換兩個變量的值。那么具體實現機制是怎樣的呢?
運行時,首先構造一個元組(y, x),然后構造另一個元組(x, y),接著用元組(y, x)賦值給(x, y),元組賦值過程從左到右,依次進行。假如x=1,y=2,先令x=y,此時x=2,然后令y=x,y應該等于2?那么就不能實現變量交換了?對于這個問題,應該從元組的特性說起。
x, y, z = 1, 2, 'a string'
tuple = (x, y, z)
變量名x, y, z都是引用,內存開辟除了三個空間分別存儲1, 2, 'a string',三個變量分別指向這三塊地址。由這三個變量構造的元組tuple,它有三個元素,這三個元素并不是x,y,z這三個變量,而是這三個變量所指向的地址空間里的內容。如果此時再另x=4,此時在地址空間會另開辟出一塊空間存儲4,x進而指向這塊空間,而元組內的三個值仍保持不變。
所以對于 x, y = y, x 來說,首先由y,x所構成的元組(y,x)其實應該表示為(2,1),那么再從左到右賦值,就可以交換變量的值了。
在函數中接收元組和列表
使函數接收元組或字典形式的參數的時候,可以分別使用 ?*?和 ?**?前綴。這種方法在函數需要獲取可變數量的參數的時候特別有用。
>>> def powersum(power, *args): ... '''Return the sum of each argument raised to specified power.''' ... total = 0 ... for i in args: ... total += pow(i, power) ... return total ... >>> powersum(2, 3, 4) 25>>> powersum(2, 10) 100由于在args變量前有*前綴,所有多余的函數參數都會作為一個元組存儲在args中。如果使用的是**前綴,多余的參數則會被認為是一個字典的鍵/值對。
字典
字典類似于你通過聯系人名字查找地址和聯系人詳細情況的地址簿,即,我們把鍵(名字)和值(詳細情況)聯系在一起。注意,鍵必須是唯一的,就像如果有兩個人恰巧同名的話,你無法找到正確的信息。
注意,你只能使用不可變的對象(比如字符串)來作為字典的鍵,但是你可以使用不可變或可變的對象作為字典的值。基本說來就是,你應該只使用簡單的對象作為鍵。
鍵值對在字典中以這樣的方式標記:d = {key1 : value1, key2 : value2 }。注意它們的鍵/值對用冒號分割,而各個對用逗號分割,所有這些都包括在花括號中。
記住字典中的鍵/值對是沒有順序的。如果你想要一個特定的順序,那么你應該在使用前自己對它們排序。
字典是dict類的實例/對象。
#!/usr/bin/python # Filename: using_dict.py# 'ab' is short for 'a'ddress'b'ookab = { 'Swaroop' : 'swaroopch@byteofpython.info','Larry' : 'larry@wall.org','Matsumoto' : 'matz@ruby-lang.org','Spammer' : 'spammer@hotmail.com'}print "Swaroop's address is %s" % ab['Swaroop']# Adding a key/value pair ab['Guido'] = 'guido@python.org'# Deleting a key/value pair del ab['Spammer']print '\nThere are %d contacts in the address-book\n'%len(ab) for name, address in ab.items():print 'Contact %s at %s' % (name, address)if 'Guido' inab:# OR ab.has_key('Guido')print "\nGuido's address is %s" % ab['Guido']結果 $ python using_dict.py Swaroop's address is swaroopch@byteofpython.infoThere are 4 contacts in the address-bookContact Swaroop at swaroopch@byteofpython.info Contact Matsumoto at matz@ruby-lang.org Contact Larry at larry@wall.org Contact Guido at guido@python.orgGuido's address is guido@python.org它如何工作
我們使用已經介紹過的標記創建了字典ab。然后我們使用在列表和元組章節中已經討論過的索引操作符來指定鍵,從而使用鍵/值對。我們可以看到字典的語法同樣十分簡單。
我們可以使用索引操作符來尋址一個鍵并為它賦值,這樣就增加了一個新的鍵/值對,就像在上面的例子中我們對Guido所做的一樣。
我們可以使用我們的老朋友——del語句來刪除鍵/值對。我們只需要指明字典和用索引操作符指明要刪除的鍵,然后把它們傳遞給del語句就可以了。執行這個操作的時候,我們無需知道那個鍵所對應的值。
接下來,我們使用字典的items方法,來使用字典中的每個鍵/值對。這會返回一個元組的列表,其中每個元組都包含一對項目——鍵與對應的值。我們抓取這個對,然后分別賦給for..in循環中的變量name和address然后在for-塊中打印這些值。
我們可以使用in操作符來檢驗一個鍵/值對是否存在,或者使用dict類的has_key方法。你可以使用help(dict)來查看dict類的完整方法列表。
關鍵字參數與字典。如果換一個角度看待你在函數中使用的關鍵字參數的話,你已經使用了字典了!只需想一下——你在函數定義的參數列表中使用的鍵/值對。當你在函數中使用變量的時候,它只不過是使用一個字典的鍵(這在編譯器設計的術語中被稱作符號表?)。
序列
列表、元組和字符串都是序列,但是序列是什么,它們為什么如此特別呢?序列的兩個主要特點是索引操作符和切片操作符。索引操作符讓我們可以從序列中抓取一個特定項目。切片操作符讓我們能夠獲取序列的一個切片,即一部分序列。
切片操作:[開始位置:結束位置:步長]
tempList=[0,1,2,3,4,5] print tempList[::4]#結果 [0, 4] 從 開始位置 到 結束位置 且步長為4的位置的值 組成一個新的List ,并打印temp = [x for x in range(11)] print tem0[::2] print temp[::] print temp[1:-1]
它如何工作
首先,我們來學習如何使用索引來取得序列中的單個項目。這也被稱作是下標操作。每當你用方括號中的一個數來指定一個序列的時候,Python會為你抓取序列中對應位置的項目。記住,Python從0開始計數。因此,shoplist[0]抓取第一個項目,shoplist[3]抓取shoplist序列中的第四個元素。
索引同樣可以是負數,在那樣的情況下,位置是從序列尾開始計算的。因此,shoplist[-1]表示序列的最后一個元素而shoplist[-2]抓取序列的倒數第二個項目。
切片操作符是序列名后跟一個方括號,方括號中有一對可選的數字,并用冒號分割。注意這與你使用的索引操作符十分相似。記住數是可選的,而冒號是必須的。
切片操作符中的第一個數(冒號之前)表示切片開始的位置,第二個數(冒號之后)表示切片到哪里結束。如果不指定第一個數,Python就從序列首開始。如果沒有指定第二個數,則Python會停止在序列尾。注意,返回的序列從開始位置開始?,剛好在結束?位置之前結束。即開始位置是包含在序列切片中的,而結束位置被排斥在切片外。
這樣,shoplist[1:3]返回從位置1開始,包括位置2,但是停止在位置3的一個序列切片,因此返回一個含有兩個項目的切片。類似地,shoplist[:]返回整個序列的拷貝。
你可以用負數做切片。負數用在從序列尾開始計算的位置。例如,shoplist[:-1]會返回除了最后一個項目外包含所有項目的序列切片。
使用Python解釋器交互地嘗試不同切片指定組合,即在提示符下你能夠馬上看到結果。序列的神奇之處在于你可以用相同的方法訪問元組、列表和字符串。
參考
當你創建一個對象并給它賦一個變量的時候,這個變量僅僅?參考?那個對象,而不是表示這個對象本身!也就是說,變量名指向你計算機中存儲那個對象的內存。這被稱作名稱到對象的綁定。
一般說來,你不需要擔心這個,只是在參考上有些細微的效果需要你注意。這會通過下面這個例子加以說明。
對象與參考
#!/usr/bin/python # Filename: reference.pyprint 'Simple Assignment' shoplist = ['apple', 'mango','carrot','banana'] mylist = shoplist # mylist is just another name pointing to the same object!del shoplist[0]print 'shoplist is', shoplist print 'mylist is', mylist# notice that both shoplist and mylist both print the same list without# the 'apple' confirming that they point to the same objectprint 'Copy by making a full slice' mylist = shoplist[:] # make a copy by doing a full slice del mylist[0]# remove first itemprint 'shoplist is', shoplist print 'mylist is', mylist# notice that now the two lists are different 輸出$ python reference.py Simple Assignment shoplist is ['mango', 'carrot', 'banana'] mylist is ['mango', 'carrot', 'banana'] Copy by making a full slice shoplist is ['mango', 'carrot', 'banana'] mylist is ['carrot', 'banana']它如何工作
大多數解釋已經在程序的注釋中了。你需要記住的只是如果你想要復制一個列表或者類似的序列或者其他復雜的對象(不是如整數那樣的簡單?對象?),那么你必須使用切片操作符來取得拷貝。如果你只是想要使用另一個變量名,兩個名稱都參考?同一個對象,那么如果你不小心的話,可能會引來各種麻煩。
給Perl程序員的注釋
記住列表的賦值語句不創建拷貝。你得使用切片操作符來建立序列的拷貝。??
更多字符串的內容
我們已經在前面詳細討論了字符串。我們還需要知道什么呢?那么,你是否知道字符串也是對象,同樣具有方法。這些方法可以完成包括檢驗一部分字符串和去除空格在內的各種工作。
你在程序中使用的字符串都是str類的對象。這個類的一些有用的方法會在下面這個例子中說明。如果要了解這些方法的完整列表,請參見help(str)。
字符串的方法
#!/usr/bin/python # Filename: str_methods.pyname = 'Swaroop' # This is a string objectif name.startswith('Swa'):print 'Yes, the string starts with "Swa"'if 'a' in name:print 'Yes, it contains the string "a"'if name.find('war') !=-1:print 'Yes, it contains the string "war"'delimiter = '_*_' mylist = ['Brazil', 'Russia','India','China'] print delimiter.join(mylist) 輸出$ python str_methods.py Yes, the string starts with "Swa" Yes, it contains the string "a" Yes, it contains the string "war" Brazil_*_Russia_*_India_*_China它如何工作
這里,我們看到使用了許多字符串方法。startwith方法是用來測試字符串是否以給定字符串開始。in操作符用來檢驗一個給定字符串是否為另一個字符串的一部分。
find方法用來找出給定字符串在另一個字符串中的位置,或者返回-1以表示找不到子字符串。str類也有以一個作為分隔符的字符串join序列的項目的整潔的方法,它返回一個生成的大字符串。
總結
以上是生活随笔為你收集整理的简明Python教程学习笔记_4_数据结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小甲鱼 OllyDbg 教程系列 (二)
- 下一篇: charles 简单使用