Python程序可以分解為模塊、語句、表達式以及對象,如下所示:
程序由模塊構成
模塊包含語句
語句包含表達式
表達式建立並出口對象
一、Python類型的介紹:
1.1 為什么使用內置類型
Python提供了強大的對象類型作為語言的組成部分,事實上,除非有內置類型無法提供的特殊對象要處理,最好總是使用內置對象而不是使用自己的實現。下面是其原因:
內置對象使程序更容易編寫:
對於簡單的任務,內置類型往往能夠表現問題領域的所有結構。例如,集合(列表)和搜索表(字典)可以馬上使用它們,僅使用python內置對象類型就能完成很多工作。
內置對象使擴展的組建:
對於較為復雜的任務,或許仍需要提供自己的對象,使用python的類或C語言的結構。例如,堆棧數據結構也許會實現為管理和定制內置列表的類。
內置對象往往比定制的數據結構更有效率:
在速度方面,python內置類型優化了用C實現數據結構算法。盡管可以實現屬於自己的類似的數據類型,但往往很難達到內置數據類型所提供的性能水平。
內置對象是語言的標准的一部分:
python不但借鑒了依靠內置工具的語言(例如LISP),而且吸取了那些依靠程序員去提供自己實現的工具或框架的語言(例如C++)的優點。盡管在Python中可以實現獨一無二的對象類型,但在開始階段並沒有必要這樣做。此外,因為Python的內置工具是標准的,他們一般都是一致的。
1.2 Python的核心數據類型
python的內置對象類型和一些編寫其常量(literal)所使用到的語法,也就是能夠生成這些對象的表達式。
內置對象:
數字、字符串、列表、字典、元組、文件、集合、其他類型、編程單元類型、與實現相關的類型
上面所列內容並不完整,因為在python程序中處理的每樣東西都是一種對象。例如,在python中進行文本模式匹配時,創建了模式對象,還有進行網絡腳本編程時,使用了套接字對象,它們由def、class、import和lamba這樣的語句和表達式創建,並且可以在腳本間自由地傳遞,存儲在其他對象中等。
1.3數字
python的核心對象集合包括常規的類型:整數、浮點數以及更為少見的類型(有虛部的復數、固定精度的十進制數、帶分子和分母的有理分數以及集合等)。
python的基本數字類型還是相當基本的。python中數字支持一般的數學運算。其中**表示乘方。
>>> 12+33 45 >>> 1.5*4 6.0 >>> 2 ** 100 1267650600228229401496703205376
#注意這里的最后一個記過:當需要的時候,python 3.0的整數類型會自動提供額外的精度,以用於較大的數值。
1.4 字符串
就像任意字符的集合一樣,字符串是用來記錄文本信息的。從嚴格意義上來說,字符串是單個字符的字符串的序列,其他類型的序列還包括列表和元組。
作為序列,字符串支持假設其中各個元素包含位置順序的操作。例如,如果我們有四個字符的字符串,我們通過內置的len函數驗證其長度並索引操作得到其各個元素。
>>> S = 'Spam' >>> len(S) 4 >>> S[0] 'S' >>> S[1] 'p'
在Python中,索引是按照最前面的偏移量進行編碼的,也就是從0開始,第一項索引為0,第二項索引為1,以此類推。
>>> S[-1] 'm' >>> S[-2] 'a' >>>
#在Python中,我們能夠反向索引,從最后一個開始(反向索引是從左邊開始計算,反向索引是從右邊開始計算)
>>> S[len(S)-1] 'm'
#一般來說,負的索引號會簡單地與字符串的長度相加,因此,上面操作和S[-1]是等效的。
>>> S[1:3] 'pa'
#除了簡單的從位置進行索引,序列也支持一種所謂分片(slice)的操作,這是一種一步就能夠提取整個分片(splice)的方法。
>>> S[1:] 'pam' >>> S[0:3] 'Spa' >>> S[:3] 'Spa' >>> S[:-1] 'Spa' >>> S[:] 'Spam'
#在一個分片中,左邊界默認為0,並且右邊界默認為分片序列的長度。
>>> S+'xyz' 'Spamxyz' >>> S*8 'SpamSpamSpamSpamSpamSpamSpamSpam'
#作為一個序列,字符串也支持使用加號進行合並(將兩個字符串合成為一個新的字符串),或者重復(通過再重復一次創建一個新的字符串)。
#注意加號(+)對於不同的對象有不同的意義:對於數字為加法,對於字符串為合並。這是Python的一般特性,也就是我們將會在本書后面提到的多態。簡而言之,一個操作的意義取決於被操作的對象。Python編寫的操作通常自動地適用於不同類型的對象。
#同時字符串還具有不可變性。如上面的例子
>>> S.find('pa') 1 >>> S.find('pd') -1 >>> S.replace('pa','XYZ') 'SXYZm' >>> S 'Spam'
#字符串的find方法是一個基本的字符串查找的操作(它將返回一個傳入字符串的偏移量,或者沒有找到的情況下返回-1),而字符串的replace方法將會對全局進行搜索和替換。
#盡管這些字符串方法的命名有改變的含義,但在這里我們都不會改變原始的字符串,而是會創建一個新的字符串作為結果------因為字符串具有不可變性。
>>> line='aaa,bbb,ccccc,dd' >>> line.split(',')#以逗號為分隔符對字符串進行切片
['aaa', 'bbb', 'ccccc', 'dd'] >>> S='spam' >>> S.upper()#將小寫轉換成大寫
'SPAM' >>> S.isalpha()#檢測是否是字母組成,布爾值,不是的話返回false。
True >>> line='aaa,bbb,ccccc,dd\n' >>> line=line.rstrip()#去掉兩邊的空格
>>> line 'aaa,bbb,ccccc,dd'
#還能實現通過分隔符將字符串拆分為子字符串(作為一種解析的簡單形式),大小寫變換,測試字符串的內容(數字、字母或其他),去掉字符串后的空格字符。
>>> 'name:%s,age:%s' %('chaishao','27')#這種就類似於位置參數,按位置將值傳給前面的%s
'name:chaishao,age:27' >>> 'chaishao:{1},age:{0}'.format(27,'chaishao')#這種還是定義位置,前面{1}和{0}表示要第二個位置的值和第一個位置的值
'chaishao:chaishao,age:27' >>> 'chaishao:{name},age:{age}'.format(name='chaishao',age=27)#這種就是前面定義變量,后面給變量賦值
'chaishao:chaishao,age:27'
#字符串還支持一個叫做格式化的高級替代操作,可以以一個表達式的形式和一個字符串方法調用。如上面的例子.
>>> dir(S) ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '_ _le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'iss pace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'sw apcase', 'title', 'translate', 'upper', 'zfill']
#對於更多的細節,可以通過調用內置的dir函數,將會返回一個列表,其中包含了對象的所有屬性。由於方法是函數屬性,他們也會在這個列表中出現。上面那些變量名中有下划線的內容,它們代表了字符串對象的實現方式,並支持定制。一般來說,以雙下划線開頭並結尾的變量名是用來表示Python實現細節的命名模式。而這個列表中沒有下划線的屬性是字符串對象能夠調用的方法。
>>> help(S.replace) Help on built-in function replace: replace(...) method of builtins.str instance S.replace(old, new[, count]) -> str Return a copy of S with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced.
#dir函數簡單地給出了方法的名稱。要查詢它們是做什么的,可以將其傳遞給help函數。就像PyDoc一樣(一個從對象中提取文檔的工具),help是一個隨Python一起分發的面向系統代碼的接口。
>>> help(S) No Python documentation found for 'spam'. Use help() to get the interactive help utility. Use help(str) for help on the str class. >>> help(str)#可以查看str的所有help幫助說明
Help on class str in module builtins:
#如上面可以直接查看所有的幫助說明就像查看man幫助一樣,不過一般還是針對某個特定的方法進行查看。
>>> S='A\nB\tC' >>> len(S)#查看字符串的長度
5 >>> ord('\n')#ord() 函數是 chr() 函數(對於8位的ASCII字符串)或 unichr() 函數(對於Unicode對象)的配對函數,它以一個字符(長度為1的字符串)作為參數,返回對應的 ASCII 數值,或者 Unicode 數值,如果所給的 Unicode 字符超出了你的 Python 定義范圍,則會引發一個 TypeError 的異常。
10 >>> S='A\0B\0C' >>> len(S) 5
#上面的反斜線轉義序列表示特殊的字符。
>>> msg=""" abc ... def'''ABC""BCD'HAHA""" >>> msg ' abc\ndef\'\'\'ABC""BCD\'HAHA' >>> print(msg) abc def'''ABC""BCD'HAHA
#Python允許字符串包括在單引號或雙引號中(他們代表着相同的東西)。它也允許在三個引號(單引號或雙引號)中包括多行字符串常量。當采用這種形式的時候,所有的行都合並在一起,並在每一行的末尾增加換行符。在Python腳本中嵌入像HTML或XML這樣的內容時,是很方便的。
1.5 列表
Python的列表對象是這個語言提供的最通用的序列。列表是一個任意類型的對象的位置相關的有序集合,它沒有固定的大小。不像字符串,其大小是可變的,通過對偏移量進行賦值以及其他各種列表的方法進行調用,確實能夠修改列表的大小。
>>> L=[123,'spam',1.23] >>> len(L) 3 >>> L[0]#查看列表的索引,下標從0開始。
123 >>> L[:-1]#也可以對列表進行分片,這里就是[0:2]
[123, 'spam'] >>> L + [4,5,6]#兩個列表可以合並
[123, 'spam', 1.23, 4, 5, 6] >>> L [123, 'spam', 1.23]
#由於列表是序列的一種,列表支持所有的我們隊字符串所討論過得序列操作。唯一的區別就是其結果往往是列表而不是字符串。
#列表和其他語言中的數組有些類似,但是列表要強大很多,其中一點就是列表沒有固定類型的約束。例如,上面的列表就包含了三個完全不同類型的對象(一個整數、一個字符串、以及一個浮點數)。此外,列表沒有固定大小,也就是說能夠按照需要增加或減少列表大小,來響應其特定的操作。
>>> L.append('NI') #在列表尾部添加一個NI >>> L [123, 'spam', 1.23, 'NI'] >>> L.pop(2) #刪除索引2也就是從左往右第三個元素 1.23 >>> L [123, 'spam', 'NI']
>>> L.insert(1,'haha') #在索引1的位置插入haha對象
>>> L
[123, 'haha', 'spam', 'NI']
>>> L.remove(123) #刪除123
>>> L
['haha', 'spam', 'NI']
#列表的append方法擴充了列表的大小並在列表的尾部插入一項;pop方法(或者等效的del語句)移除給定偏移量的一項,從而讓列表減小。其他的列表方法可以在任意位置插入(insert)元素,按照值移除(remove)元素等。因為列表是可變的,大多數列表的方法都會就地改變列表對象,而不是創建一個新的列表。
>>> list1=['bb','aa','cc'] >>> list1.sort() #對列表進行排序默認是按照升序排序
>>> list1 ['aa', 'bb', 'cc'] >>> list1.reverse()#對列表進行翻轉
>>> list1 ['cc', 'bb', 'aa']
#列表sort方法是對列表排序的意思,這些方法都會直接對列表進行改變。
>>> list1[1] #查找list1列表偏移量是1也就是第二個元素 'bb' >>> list1[3] #超出邊界直接會報錯 Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range
>>> list1[1]='BB' #對列表第二個元素重新賦值
>>> list1[3]='CC' #超出列表末尾范圍之外賦值會報錯
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
>>> list1
['cc', 'BB', 'aa']
#盡管列表沒有固定的大小,Python扔不允許引用不存在的元素。超出列表末尾之外的索引總是會導致錯誤,對列表末尾范圍之外賦值也是如此。這是有意而為之的,由於去給一個列表邊界外的元素賦值,往往會得到一個錯誤(而在C語言中情況比較糟糕,因為它不會像Python這樣進行錯誤檢查)。在Python中,並不是默默的增大列表作為響應,而是會提示錯誤。為了讓一個列表增大,可以調用類似於append這樣的列表方法。
>>> M=[[1,2,3],[4,5,6],[7,8,9]] >>> M [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> M[1] #獲取第二個元素的值
[4, 5, 6]
>>> M[1][2] #獲取第二個元素里面嵌套的列表的第三個元素的值
6
#Python核心數據類型的一個優秀的特性就是他們支持任意的嵌套。能夠以任意的組合對其進行嵌套,並可以多個層次進行嵌套(例如,能夠讓一個列表包含一個字典,並在這個字典中包含另一個列表等)。這種特性的一個直接的應用就是實現矩陣,或者Python中的“多維數組”,一個嵌套列表的列表就能完成這個基本的操作。上面我們編寫了一個包含3個其他列表的列表。其效果就是表現了一個3*3的數字矩陣。
>>> col2 = [row for row in M] #for row in M是一個for循環,那么row久代表了M里面的三個元素,所以col2的值就是M的值
>>> col2 [[1, 2, 3], [4, 5, 6], [7, 8, 9]] >>> col2=[row[1] for row in M] #這里row[1]就相當於取M[1]
>>> col2 [2, 5, 8]
#列表解析,處理序列的操作和列表的方法中,Python還包括了一個更高級的操作,成為列表解析表達式,從而提供了一個處理像矩陣這樣結構的強大工具。列表解析源自集合的概念。它是一種通過對序列中的每一項運行一個表達式來創建一個新列表的方法,每次一個,從左至右。列表解析是編寫在方括號中的,並且由使用了同一個變量名的(這里是row)表達式和循環結構組成。上面的這個列表解析表達基本上就是它字面上所講的,把矩陣M的每個row中的row[1]放到一個新的列表中。
>>> col2 [2, 5, 8] >>> [row[1]+1 for row in M] #把它搜集到的每一個元素都加1
[3, 6, 9] >>> [row[1] for row in M if row[1] % 2 == 0] #使用if條件語句,通過使用%求余表達式(取余數)過濾了結果中的奇數。
[2, 8]
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> diag = [M[i][i] for i in [0,1,2]] #M[i][i]就相當於M[0][0],M[1][1],M[2][2]
>>> diag
[1, 5, 9]
>>> doubles = [c*2 for c in 'spam'] #取出來的值*2
>>> doubles
['ss', 'pp', 'aa', 'mm']
>>> G = (sum(row) for row in M) #讓row求和,因為是for循環嘛,這里的意思就相當於讓M[0],M[1],M[2]分別求和
>>> next(G) #next() 返回迭代器的下一個項目
6
>>> next(G)
15
>>> next(G)
24
>>> list(map(sum,M)) #內置map可以做上面類似的事情,產生對各項運行一個函數的結果,在Python 3.0中,將其包裝到列表中,會使其返回所有值。
[6, 15, 24]
>>> {sum(row) for row in M} #可以用解析語法來創建一個集合
{24, 6, 15}
>>> {i : sum(M[i]) for i in range(len(M))} #可以用解析語法來創建一個字典
{0: 6, 1: 15, 2: 24}
#實際應用中的列表解析可以更復雜,如上面。列表解析創建了新的列表作為結果,但是能夠在任何可迭代的對象上進行迭代。
#列表解析以及相關的內容函數map和filter比較復雜,這里記錄一下先。實際上,在python 3.0中,列表、集合和字典都可以用解析來創建。
1.6 字典
Python中的字典是完全不同的東西:它們不是序列,而是一種映射(mapping)。映射是一個其他對象的集合,但是它們是通過鍵而不是相對位置來存儲的。實際上,映射並沒有任何可靠的從左至右的順序。它們簡單地將鍵映射到值。字典是Python核心對象集合中的唯一的一種映射類型,也具有可變性------可以就地改變,並可以隨需求增大或減小、就像列表那樣。
>>> D={'food':'Spam','quantity':4,'color':'pink'}#定義一個字典D
>>> D['food']#字典food鍵的值
'Spam' >>> D['quantity'] += 1#字典quantity的值加1
>>> D {'color': 'pink', 'food': 'Spam', 'quantity': 5}
#上面是映射操作,作為常量編寫時候,字典編寫在大括號中,並包含一系列的“鍵:值”對。在我們需要將鍵與一系列值相關聯(例如,為了表述某物的某屬性)的時候,字典是很有用的。上面的例子是一個包含了三個元素的字典(鍵分別為“food”、“quantity”和“color”)。通過鍵對字典進行索引來讀取或改變鍵所關聯的值。字典的索引操作使用的是和序列相同的語法,但是在方括號中的元素是鍵,而不是相對位置。上面就是使用大括號這種常量形式。
>>> D={}#先定義一個空字典
>>> D['name']='chaishao'#通過給這種定義鍵值對的形式直接給字典賦值
>>> D['job']='dev' >>> D['age']=27 >>> D {'age': 27, 'name': 'chaishao', 'job': 'dev'} >>> print(D['name']) chaishao
#上面就是一種創建空字典,然后每次以一個鍵來填寫它的方式。與列表中禁止邊界外的賦值不同,對一個新的字典的鍵賦值會創建該鍵。
#上面最后一個例子,實際是使用字典的鍵來搜索對應的值,在別的應用中,字典可以用來執行搜索,通過鍵索引一個字典往往是Python中編寫搜索的最快方法。
>>> rec = {'name':{'first':'chai','last':'shao'},#記錄了姓和名,這就屬於字典嵌套字典
... 'job':['dev','mgr'],#記錄了職位和角色,這就是嵌套了列表
... 'age':27}
>>> rec
{'age': 27, 'name': {'last': 'shao', 'first': 'chai'}, 'job': ['dev', 'mgr']}
>>> rec['name'] #查找字典rec關於name鍵的值
{'last': 'shao', 'first': 'chai'}
>>> rec['name']['last'] #查找字典rec關於name鍵中的last鍵的值
'shao'
>>> rec['job']
['dev', 'mgr']
>>> rec['job'][-1]#查找rec字典中job鍵中列表最后一個元素的值
'mgr'
>>> rec['job'].append('CTO') #給rec字典中的job鍵中的列表加入一個CTO的值
>>> rec
{'age': 27, 'name': {'last': 'shao', 'first': 'chai'}, 'job': ['dev', 'mgr', 'CTO']}
#上面在頂層使用了三個鍵的字典(鍵分別是“name”、“job”和“age”),但是值的情況變得復雜得多:一個嵌套的字典作為name的值,支持了多個部分,並用一個嵌套的列表作為job的值從而支持多個角色和未來的擴展。能夠獲取這個結構的組件,就像之前在矩陣中所作的那樣,但是這次索引的是字典的鍵,而不是列表的偏移量。
#注意這里的最后一個操作是如何擴展嵌入job列表的。因為job列表是字典所包含的一部分獨立的內存,它可以自由的增加和減少。
>>> rec=0 >>> rec 0
#在Python中,當最后一次引用對象后(例如,將這個變量用其他的值進行賦值),這個對象所占用的內存空間將會自動清理掉,類似於上面那種。從技術上來說,Python具有一種叫做垃圾收集的特性,在程序運行時可以清理不再使用的內存,並將你從必須管理代碼中這樣的細節中解放出來。在Python中,一旦一個對象的最后一次引用被移除,空間將會立即回收。
>>> D = {'a':1,'d':2,'c':3} >>> Ks = list(D.keys()) #將字典D的鍵做成列表賦值給Ks
>>> Ks
['a', 'd', 'c'] >>> Ks.sort() #進行一下排序
>>> Ks ['a', 'c', 'd'] >>> D = {'a':1,'c':2,'b':3} >>> D ##字典不是序列,它們並不包含任何可靠的從左至右的順序,這意味着如果我們建立一個字典,並將它打印出來,它的鍵也許會以與我們輸入時不同的順序出現。
{'a': 1, 'b': 3, 'c': 2} >>> Ks = list(D.keys())
>>> Ks.sort()
>>> for key in Ks: #寫個for循環
... print(key,'=>',D[key]) #循環打印key的名稱和D字典里key的值
... #按一次回車是繼續寫,我們要出結果所以需要按兩次回車
a => 1 b => 3 c => 2
#上面的例子如果一個字典的元素中,需要強調鍵的某種順序的話,常用的解決辦法就是通過字典的keys方法收集一個鍵的列表,然后使用列表的sort方法進行排序,然后使用Python的for循環逐個進行顯示結果。
>>> for key in sorted(D): ... print(key,'=>',D[key])#注意這里,要按個空格再打print啊,不然按回車要報錯的。
... a => 1 c => 3 d => 2
#通過使用最新的sorted內置函數就可以一步完成上面對key的排序。sorted調用返回結果並對各種對象類型進行排序,上面的例子就是自動對字典的鍵排序。
>>> squares = [x ** 2 for x in [1,2,3,4,5]] >>> squares [1, 4, 9, 16, 25] >>> squares1=[] >>> for x in [1,2,3,4,5]:#編寫了一個等效的for循環,通過在運行時手動增加列表來創建最終的列表。
... squares1.append(x ** 2) ... >>> squares [1, 4, 9, 16, 25]
#迭代和優化,for循環是真正通過的迭代工具。事實上,它們都能夠工作於遵守迭代協議(這是Python中無處不在的一個概念,表示在內存中物理存儲的序列,或一個在迭代操作情況下每次產生一個元素的概念,表示在內存中物理存儲的序列,或一個在迭代操作情況下每次產生一個元素的對象)的任意對象。如果一個對象在響應next之前先用一個對象對iter內置函數做出響應,那么它屬於后一種情況。我們在前面所見到生成器解析表達式就是這樣的一個對象。
#從左到右掃描一個對象的每個Python工具都使用迭代協議。這就是上上個例子介紹的sorted調用直接工作於字典之上,我們不必調用keys方法來得到一個序列,因為字典是可迭代的對象,可以用一個next返回后續的鍵。這也就一意味着像上面任何列表解析表達式都可以計算一列數字的平方。
#盡管這樣,列表解析和相關的函數編程工具,如map和filter,通常運行得比for循環快:這是對有大數據集合的程序有重大影響的特性之一。在Python中性能測試是一個很難應付的任務,因為它在反復地優化。
#Python中的一個主要原則就是,首先為了簡單和可讀性去編寫代碼,在程序可以工作,並證明了確實有必要考慮性能后,再考慮該問題。更多的情況是代碼本身就已經足夠快了。如果確實需要提高代碼的性能,那么Python提供了幫助你實現的工具,包括time以及timeit模塊和profile模塊。
>>> D {'a': 1, 'd': 2, 'c': 3} >>> D['e'] = 99 #雖然能夠通過給新的鍵值來擴展字典
>>> D {'a': 1, 'e': 99, 'd': 2, 'c': 3} >>> D['f'] #但是獲取一個不存在的鍵值仍然是一個錯誤
Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'f' >>> 'f' in D #編寫程序時並不是總是知道當前存在什么鍵,可以通過in關系表達式,來查詢字典中的一個鍵是否存在。
False >>> if not 'f' in D: #也可以通過使用Python的If語句對結果進行分支處理
... print('missing') ... missing
>>> value = D.get('x',0) #這是另外一種方法,如果獲取鍵失敗就給賦值0
>>> value
0
>>> value = D['f'] if 'f' in D else 0 #這是跟if結合,如果f鍵存在就將f的值賦給value,否則賦值0
>>> value
0
#默認情況下,if語句也可以有else分句,以及一個或多個elif(else if)分句進行其他的測試。它是Python主要的選擇工具,並且是腳本中編寫邏輯的方法。
1.7 元組
元組對象(tuple)基本上就像一個不可以改變的列表。就像列表一樣,元組是序列,但是它具有不可變性,和字符串類似。從語法上講,它們編寫在圓括號中而不是方括號中,它們支持任意類型、任意嵌套以及常見的序列操作。
>>> T = (1,2,3,4) #定義一個元組
>>> len(T) 4 >>> T + (5,6) #兩個元組合並
(1, 2, 3, 4, 5, 6) >>> T[1] #查找元組偏移量是1的也就是第二個元素
2 >>> T.index(4) #查找元素4所在的索引位置
3 >>> T.count(4) #查找4這個元素在元組中出現的次數
1 >>> T[0] = 2 #元組是不可變的,如果想改變元組的值直接就報錯了
Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment
#上面就是元組的常用操作以及不可變的演示。
>>> T = ('spam',3.0,[1,2,3]) #元組也支持混合的類型和嵌套
>>> T[1] #查找偏移量是1的值
3.0 >>> T[2][2] #查找偏移2也就是最后的列表中的第三個元素
3 >>> T.append(4) #元素不能增長或縮短,因為它們是不可變的
Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'tuple' object has no attribute 'append'
#為什么要用元組呢,它的關鍵是不可變性。如果在程序中以列表的形式傳遞一個對象的集合,它可能在任何地方改變;如果使用元組的話,則不能。
1.8 文件
文件對象是Python代碼對電腦上外部文件的主要接口。雖然文件是核心類型,但是它有些特殊:沒有特定的常量語法創建文件。要創建一個文件對象,需調用內置的open函數以字符串的形式傳遞給它一個外部的文件名以及一個處理模式的字符串。
>>> f = open('data.txt','w') #以寫的方式打開文件
>>> f.write('Hello\n') #寫入Hello並換行
6 >>> f.write('world\n') #寫入world並換行
6 >>> f.close() #關閉文件,就會把寫的內容寫入到文件
#例如上面,創建一個文本輸出文件,可以傳遞其文件名以及‘w’處理模式字符串以寫數據,這樣就在當前文件夾下創建了一個文件,並向它寫入文本(文件名可以是完整的路徑)。
>>> f=open('data.txt') >>> text = f.read() >>> text 'HelloHello\nworld\n' >>> print(text) HelloHello world >>> text.split() ['HelloHello', 'world']
#上面的例子是打開文件,默認就是r類型,然后將文件的內容讀至一個字符串,並顯示它。對腳本而言,文件的內容總是字符串,無論文件包含的數據是什么類型。
#文化提供了多種讀和寫的方法(read可以接受一個字節大小的選項,readline每次讀一行等),以及其他的工具(seek移動到一個新的文件位置)。讀取一個文件的最佳方式就是根本不讀它,文件提供了一個迭代器(iterator),它在for循環或其他環境中自動地一行一行地讀取。
#其他文件類工具:open函數能夠實現在Python中編寫的絕大多數文件處理。盡管這樣,對於更高級的任務,Python還有額外的類文件工具:管道、先進先出隊列(FIFO)、套接字、通過鍵訪問文件、對象持久、基於描述符的文件、關系數據庫和面向對象數據庫接口等。例如,描述符文件(descriptor file)支持文件鎖定和其他的底層工具,而套接字提供網絡和進程間通信的接口。
1.9 其他核心類型
集合,它不是映射也不是序列,相反,它是唯一的不可變的對象的無序集合。集合可以通過調用內置set函數而創建,或者使用Python 3.0中新的集合常量和表達式創建,並且它支持一般的數學集合操作。
http://www.cnblogs.com/chaishao/p/5759436.html #開頭部分對集合的介紹和文件的介紹。
二、數字
2.1 數字類型介紹
Python的數字類型是相當典型的,在Python中,數字並不是一個真正的對象類型,而是一組類似類型的分類。Python不僅支持通常的數字類型(整數和浮點數),而且能夠通過常量直接創建數字以及處理數字的表達式。此外,Python為更高級的工作提供了很多高級數字編程支持和對象。Python數字類型的完整工具包括:
整形和浮點數、復數、固定精度的十進制數、有理分數、集合、布爾類型、無窮的整數精度、各種數字內置函數和模塊。
數字常量:在基本類型中,Python提供了:整數(正整數和負整數)和浮點數(帶小數部分的數字)。Python還允許我們使用十六進制、八進制常量來表示整數,提供一個復數類型,並且允許整數具有無窮的精度(只要內存空間允許,它可以增長成任意位數的數字)。下面展示了Python數字類型在程序中的顯示方式(作為常量):
#一般來說,Python的數字類型是很容易使用的,除了內置數字常量之外,Python還提供了一系列處理數字對象的工具:
表達式操作符:+、-、*、\、>>、**、&等
內置數學函數:pow、abs、round、int、hex、bin等
公用模塊:random、math等
2.2 Python表達式操作符
表達式式處理數字的最基本的工具。當一個數字(或其他對象)與操作符想結合時,Python執行時將計算得到一個值。在Python中,表達式式使用通常的數學符號和操作符號寫出來的。除了常用的是加減乘數,%是計算余數操作符、<<執行左移位、&計算位與的結果等。其他的則更Python化一些,並且不全都具備數值特征。例如,is操作符測試對象身份(也就是內存地址,嚴格意義上的相等),lambda創建匿名函數。
Python表達式操作符及程序:
下面是Python2.6和Python3中操作符的版本差異和最新添加:
1. 在python 2.6版中,值不相等可以寫成X != Y或X <> Y.在python 3.0之中,后者會被移除,因為它是多余的。值不相等測試使用X != Y就行了。
2. 在Python 2.6中,一個后引號表達式‘X’和repr(X)的作用相同,轉換對象以顯示字符串。由於其不好理解,Python 3.0刪除了這個表達式,使用更容易理解的str和repr內置函數。
3. 在Python 2.6和Python 3.0中,floor除法表達式(X // Y)總是會把余數小數部分去掉。在Python 3.0中,X / Y表達式執行真正的除法(保留余數)和Python 2.6中的傳統除法(截除為整數)。
4. 列表語法([...])用於表示列表常量或列表解析表達式。后者是執行隱形循環,把表達式的結果收集到新的列表中。
5. (...)語法用於表示雲組和表達式,以及生成器表達式,后者是產生所需結果的列表解析的一種形式,而不是構建一個最終的列表。
6. {...}語法表示字典常量,並且在Python 3.0中可以表示集合常量以及字典和集合解析。
7. yield和三元選擇表達式和Python 2.5及其以后的版本中可用。前者返回生成器中的send(...)參數,后者是一個多行if語句的縮寫形式。如果yield不是單獨地位於一條賦值語句的右邊的話,需要用圓括號。
8. 比較操作符可以連續使用:X <Y <z的結果與X < Y < X相同。
9. 在最近的Python中,分片表達式X[I:J:K]等同於同一個分片對象索引:X[slice(I,J,K)]。
10. 在Python 3.0中,對字典的大小比較也不再支持(盡管支持相等性測試);比較sorted(dict.items())是一種可能的替代。
2.3 十六進制、八進制和二進制記數
Python證書能夠以十六進制、八進制和二進制記數法來編寫,作為一般的以10位基數的十進制記數法的補充。這些常量只是指定一個整數對象的值的一種替代方法,例如,Python 3.0和Python 2.6中的如下常量編碼會產生具有3種進制的指定值的常規整數:
>>> 0o1,0o20,0o377 #八進制
(1, 16, 255) >>> 0x01,0x10,0xFF #十六進制
(1, 16, 255) >>> 0b1,0b100000,0b111111111 #二進制
(1, 32, 511) >>> 0b1,0b10000,0b111111111 (1, 16, 511) #都表示十進制的數
>>> oct(255),hex(255),bin(255) #將十進制數字轉變成對應的進制數
('0o377', '0xff', '0b11111111')
>>> int('255'),int('377',8),int('ff',16),int('11111111',2)
(255, 255, 255, 255)
>>> int('255'),int('0o377',8),int('0xff',16),int('0b11111111',2)
(255, 255, 255, 255)
#oct函數會將十進制數轉換為八進制數,hex函數會將十進制轉換為十六進制數、而bin會將十進制數轉換為二進制。另一種方式,內置的Int函數會將一個數字的字符串變換為一個整數,並可以通過定義的第二個參數來確定變換后的數字的進制。
2.4 位操作
除了一般的數學運算(加法、減法等),Python也支持C語言中大多數數學表達式。這包括哪些把整數當做二進制位串對待的操作。
>>> x = 1 #換算成二進制這就相當於0001
>>> x << 2 #二進制逢2進位,0001左移動兩位,變成了0100,就表示十進制的4了
4 >>> x | 2 #這是二進制的或運算,前面的是0001后面的是0010,所以就是0001|0010=0011,換算成十進制就是3了
3 >>> x & 1 #這個就是與的關系,就是0001&0001=0001,也就是1
1
>>> x & 2 #這個就是0001&0010=0000,也就是0
0
#像上面這樣按位進行掩碼的運算,使我們可以對一個整數進行多個標志位和值進行編碼。在這個領域里,Python 2.6 和Python 3.0中都支持的二進制和十六進制變得特別有用,它們允許我們按照位字符串來編寫和查看數字。如果Python代碼必須與由C程序生成的網絡包或封裝了的二進制數打交道的話,它是很實用的。盡管這樣,注意位操作在Python這樣的高級語言中並不像在C這樣的底層語言中那么重要。
2.5 其他的內置數學工具
除了核心對象類型以外,Python還支持用於數字處理的內置函數和內置模塊。例如,內置函數pow和abs,分別計算冪和絕對值,這里有一些內置match模塊(包含在C語言中math庫中的絕大多數工具)的例子並有一些實際中的內置函數。
>>> import math >>> math.pi,math.e (3.141592653589793, 2.718281828459045) >>> math.sin(2 * math.pi / 180) 0.03489949670250097 >>> math.sqrt(144),math.sqrt(2) (12.0, 1.4142135623730951) >>> pow(2,4),2 ** 4 (16, 16) >>> abs(-42.0),sum((1,2,3,4)) (42.0, 10) >>> min(3,1,2,4),max(3,1,2,4) (1, 4)
>>> math.floor(2.567),math.floor(-2.567)
(2, -3)
>>> math.trunc(2.567),math.trunc(-2.567)
(2, -2)
>>> int(2.567),int(-2.567)
(2, -2)
>>> round(2.567),round(2.467),round(2.567,2)
(3, 2, 2.57)
>>> (1/3),round(1/3),('%.2f'%(1/3))
(0.3333333333333333, 0, '0.33')
>>> (1/3),round(1/3,2),('%.2f'%(1/3))
(0.3333333333333333, 0.33, '0.33')
>>> '%.1f' % 2.567, '{0:.2f}'.format(2.567)
('2.6', '2.57')
#這里展示的的sum函數作用於數字的一個序列,min和max函數接受一個參數序列或者單個的參數。有各種各樣的方法可以刪除一個浮點數的小數位。
#上線也介紹了截斷和floor方法,也可以用round,不管是為了求值還是為了顯示。
#最后一個例子產生了我們通常會打印出的字符串,並且它支持各種格式化選項。
>>> import math >>> math.sqrt(144) 12.0 >>> 144 ** .5 12.0 >>> pow(144, .5) 12.0 >>> math.sqrt(1234567890) 35136.41828644462 >>> 1234567890 ** .5 35136.41828644462 >>> pow(1234567890, .5) 35136.41828644462
#在Python中有3種方法可以計算平方根:使用一個模塊函數、一個表達式或者一個內置函數。注意內置math這樣的模塊必須先導入,但是abs這樣的內置函數不需要導入就可以直接使用,換句話說,模塊是外部的組件,而內置函數位於一個隱性的命名空間內,Python自動搜索程序的變量名。這個命名空間對應於Python 3.0中名為builtins的模塊。
>>> import random >>> random.random() #選出一個0到1之間的任意浮點數
0.7293494111854583 >>> random.random() 0.7408299666488919 >>> random.randint(1,10) #選出1到10之間的隨機整數
6 >>> random.randint(11,100) 37 >>> random.choice(['A','B','C']) #在一個序列中任意挑選一項
'A' >>> random.choice(['A','B','C']) 'C'
#一般模塊都是導入才能使用的,上面使用標准庫中的random模塊時必須導入。
2.6 其他數字類型
Python的核心數字類型:整數、浮點數和復數。對於絕大多數程序員來說,需要進行的絕大多數數字處理都滿足了。不過,Python還自帶了一些更少見的數字類型。
小數數字:
比其他數據類型復雜一些,小數是通過一個導入的模塊調用函數后創建的,而不是通過運行常量表達式創建的。從功能上來說,小數對象就像浮點數,只不過它們由固定的位數和小數點,因此小數是有固定的精度的浮點值。例如,使用小數對象,我們能夠使用一個只保留兩位小數位精度的浮點數。此外,能夠定義如何省略和截斷額外的小數數字,盡管它對平常的浮點數類型來說帶來了微小的性能損失,小數類型對表現固定精度的特性(例如,錢的總和)以及實現更好的數字精度是一個理想的工具。
>>> 0.1 + 0.1 + 0.1 - 0.3 #得出來的非0確實一個浮點數 5.551115123125783e-17 >>> print(0.1 + 0.1 + 0.1 - 0.3) 5.551115123125783e-17 >>> from decimal import Decimal >>> Decimal('0.1') + Decimal('0.1') + Decimal('0.1') - Decimal('0.3') Decimal('0.0')
#從上面的例子可以看出,浮點數缺乏精確性,因為用來存儲數值的空間有限。結果接近0但是卻沒有足夠的位數去實現這樣的精度。正如上面顯示的,能夠通過調用在decimal模塊中的Decimal的構造函數創建一個小數對象,並傳入一個字符串,這個字符串有我們希望在結果中顯示的小數位數。當不同的精度的小數在表達式中混編時,python自動升級為小數位數最多的。
>>> import decimal >>> decimal.Decimal(1) / decimal.Decimal(7) Decimal('0.1428571428571428571428571429') >>> decimal.getcontext().prec=4 #設置輸出為小數點后4位 >>> decimal.Decimal(1) / decimal.Decimal(7) Decimal('0.1429') >>> 1999 + 1.33 2000.33 >>> decimal.getcontext().prec=2 >>> pay = decimal.Decimal(str(1999 + 1.33)) >>> pay Decimal('2000.33')
#可以設置全局精度,decimal模塊中的其他工具可以用來設置所有小數數值的精度、設置錯誤處理等。例如,這個模塊中的一個上下文對象允許指定精度(小數位數)和舍入模式(舍去、進位等)。該精度全局性地適用於調用線程中創建的所有小數。
另外還有分數,可以用Fraction模塊。
2.7 集合
Python 2.4引入了一種新的類型--集合(set),這是一些唯一的、不可變的對象的一個無序集合(collection),這些對象支持與數學集合理論相應的操作。根據定義,一個項在集合中只能出現一次,不管將它添加了多少次。同樣,集合有着廣泛的應用,尤其是在涉及數字和數據庫的工作中。
因為它是其他對象的集合,因此,它具有列表和字典這樣的對象的某些共同行為。例如集合是可以迭代的,可以根據需要增長或縮短,並且能夠包含各種對象類型。將會看到,一個集合的行為很像一個無值的字典的鍵,但是,它還支持額外的操作。
然而由於集合是無序的,並且不會把鍵匹配到值,他們既不是序列也不是映射類型;它們是自成一體的類型。
>>> x = set('abcde') #通過用set的方式來創建集合 >>> y = set('bdxyz') >>> type(x) #可以查看一下x的類型
<class 'set'> >>> x #輸出一下可以看出集合是無序的
{'a', 'd', 'e', 'c', 'b'} >>> 'e' in x #如果e在集合x中就為真
True >>> x - y #求差集,在x中但沒有在y中的元素
{'a', 'c', 'e'} >>> x | y #x和y的並集
{'a', 'b', 'd', 'c', 'e', 'x', 'z', 'y'} >>> x & y #x和y的交集
{'d', 'b'} >>> x ^ y #對稱差集,項目出現在x或者y中,但是不會同時出現在兩者之中
{'a', 'c', 'e', 'x', 'z', 'y'} >>> x > y, x < y #測試y中的元素是否都在x中,或者x的元素都在y中
(False, False)
>>> x=set('abcd')
>>> y=set('abc')
>>> x > y, x < y
(True, False)
#集合通過表達式操作符支持一般的數學集合運算。注意,不能再一般序列上應用這些表達式,必須通過序列創建集合后才能使用這些工具。
>>> z = x.intersection(y) #返回一個新的集合,包含x和y中的公有的元素
>>> z {'a', 'c', 'b'} >>> z.add('SPAM') #將SPAM添加到z集合中
>>> z {'a', 'SPAM', 'c', 'b'}
>>> z.update(set(['X','Y'])) #在z集合中添加一個集合,不加set也可以里面添加列表什么的,也就是添加多個元素
>>> z {'a', 'X', 'SPAM', 'Y', 'c', 'b'} >>> z.remove('b') #刪除z集合中的b元素
#除了表達式,集合對象還提供了對應這些操作的方法,以及更多的支持改變集合的方法,集合add方法插入一個項目、update是按位置求並集,remove根據值刪除一個項目(在任何集合實例或集合類型名上運行dir來查看所有可用的方法)。
>>> for item in set('abc'): print(item *3) #支持for循環
... aaa ccc bbb >>> S = set([1,2,3])
>>> S | set([3,4])
{1, 2, 3, 4} >>> S | [3,4] #集合和列表是不能進行上面的那些差集之類的
Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for |: 'set' and 'list' >>> S.union([3,4]) #返回一個新的集合,返回S和【3,4】中的相同元素以外的所有元素
{1, 2, 3, 4} >>> S.intersection((1,3,5)) #這就是求S和(1,3,5)的交集
{1, 3} >>> S.issubset(range(-5,5)) #判斷S中的每一個元素是否都在(-5,5)中
True
#上面的例子可以看出,作為可迭代的容器,集合也可以用於len、for循環和列表解析這樣的操作中。然而,由於它們都是無序的,所以不支持像索引和分片這樣的操作,盡管上上面介紹的集合表達式通常需要兩個集合,但是上面的例子可以看出,他們基於方法的對應形式往往對任何可迭代類型也有效。
#我這里用的是Python 3.0,可以看出集合輸出的是一個字典的花括號的形式,這個語法是有意義的,因為集合基本上就像是無值的字典,集合的項是無序的、唯一的、不可改變的,因此,他們的行為和字典的鍵很像。由於字典鍵列表在Python 3.0中是視圖對象,它支持像交集和並集這樣的類似集合的行為這種相似性更加驚人。
#注意,在Python中{}仍然是一個字典。空的集合必須通過內置函數set來創建。
#不可變限制和凍結集合。集合是強大而靈活的對象,但是,它們只能包含不可變(即可散列)對象類型。因此,列表和字典不能嵌入到集合中,但是,如果需要存儲復合值的話,元組是可以嵌入的。例如,集合中的元組可以用來表示日期、記錄、IP地址等。集合本身也是不可改變的,因此,不能直接嵌入到其他集合中;如果需要在另一個集合中存儲一個集合,可以像調用set一樣來調用frozenset,但是,它創建一個不可變的集合,該集合不可修改並且可以嵌套到其他集合中。
#為什么使用集合?集合操作有各種各樣常見的用途,其中一些比數字更加實用。例如,由於項在集合中只能存儲一次,集合(set)可以用來把重復項從其他集合(collection)中過濾掉。直接把集合(collection)轉換為一個集合(set),然后再轉換回來即可(因為集合是可迭代的,這里的list調用對其有效):如下面的例子
>>> L = [1,2,1,3,2,4,5] >>> set(L) {1, 2, 3, 4, 5} >>> L = list(set(L)) >>> L [1, 2, 3, 4, 5] >>> type(L) <class 'list'>
#當遍歷圖形或其他的回環結構的時候,集合可以用來記錄已經訪問過的位置。當傳遞性模塊重載和繼承樹列表程序實例,必須確保訪問過的項不再循環。盡管把訪問狀態作為鍵記錄到字典中很搞笑,但集合提供了幾乎等同的一種替代方式。
#最后在處理較大的數據集合的時候(例如,數據庫查詢結果),兩個集合的交集包含了兩個領域中共有的對象,並集包含了兩個集合中的所有項目。
2.8 布爾型
對於Python的布爾類型有一些爭論,bool原本是一個數字,因為它有兩個值True和False,不過是整數1和0以不同的形式顯示后的定制版本而已。
Python如今正式地有了一種明確的布爾型數據類型,叫做bool,其值為True和False,並且其值True和False是預先定義的內置的變量名。在內部在新的變量名True和False是bool的實例,實際上僅僅是內置的整數類型int的子類(以面向對象的觀點來看)。True和False的行為和整數1和0是一樣的,除了它們有特定的顯示邏輯:它們是作為關鍵字True和False顯示的,而不是數字1和0(從技術上來講,bool為它的兩個對象重新定義了str和repr的字符串格式)。
由於這個定制,布爾表達式和交互提示模式的輸出就作為關鍵字True和False來顯示,而不是曾經的1和0.此外,布爾型讓真值更精確。例如,一個無限循環現在能夠編寫成while True:而不是while 1:。類似地,通過使用flag = False,可以更清楚地設置標志位。
還有對於其他實際的用途,你能夠將True和False看做是預定義的設置為整數1和0的變量。大多數程序員都曾把True和False預先賦值為1和0:因為True僅僅是定制了顯示格式的整數1,在Python中True+4得到了5!
>>> type(True) <class 'bool'> >>> isinstance(True,int) True >>> True == 1 True >>> True is 1 False >>> True or False True >>> True + 4 5
#上面的例子就是對上面介紹的一種展示.
三、動態類型
3.1 變量、對象和引用
當在Python中運行賦值語句a = 3時就屬於:
變量創建:一個變量(也就是變量名),就像a,當代碼第一次給它賦值時就創建了它。之后的賦值將會改變已創建的變量名的值。
變量類型:變量永遠不會有任何的和它有關聯的類型信息或約束。類型的概念是存在對象中而不是變量名中,變量原本是通用的,它只是在一個特定的時間點,簡單的引用一個特定的對象而已。
變量使用:當變量出現在表達式中時,它會馬上被當前引用的對象所代替,無論這個對象是什么錯誤。此外,所有的變量必須在使用前明確地賦值,使用未賦值的變量會產生錯誤。
總而言之,變量在賦值的時候才創建,它可以引用任何類型的對象,並且必須在引用之前賦值。
在Python中,每當一個變量名被賦予了一個新的對象,之前的那個對象站應用的空間就會被回收(如果它沒有被其他的變量名或對象所引用的話)。這種自動回收對象的空間的技術叫做垃圾收集。
在內部,Python它在每個對象中保持了一個計數器,計數器記錄了當前指向該對象的引用數目。一旦(並精確在同一時間)這個計數器被設置為零,這個對象的內存空間就會自動回收。在前面的介紹中,假設每次x都被賦值給一個新的對象,而前一個對象的引用計數器為零,就會導致它的空間被回收。
3.2 共享引用
在交互模式下,引入另一個變量,並看一下變量名和對象的變化:
>>> a = 3 >>> b = a >>> b 3
#像上面那樣,實際的效果是變量a和b都引用了相同的對象(也就是說指向了相同的內存空間)。這在Python中叫做共享引用--多個變量名引用了同一個對象。
>>> a = 3 >>> b = a >>> a = 'spam' >>> b 3
#從上面的例子可以看出,雖然a指向了新的對象,但是b還是使用原來的變量也就是使用原來的內存空間。要想b跟着變化還得再來下b=a。
>>> L1 = [2,3,4] >>> L2 = L1 >>> L1[0] = 24 >>> L1 [24, 3, 4] >>> L2 [24, 3, 4]
#上面的例子是共享引用和在原處修改的例子,上面的例子,沒有改變L1,改變了L1所引用的對象的一個元素。這類修改會覆蓋列表對象中的某部分。因為這個列表對象是與其他對象共享的(被其他對象引用),那么一個像這樣在原處的改變不僅僅會對L1有影響。也就是說,必須意識到當做了這樣的修改,它會影響程序的其他部分。這里也對L2產生影響,因為它與L1都引用了相同的對象。另外,我們實際上並沒有改變L2,但是它的值將發生變化,因為它已經被修改了。
>>> L1 = [2,3,4] >>> L2 = L1[:] >>> L1[0] = 24 >>> L1 [24, 3, 4] >>> L2 [2, 3, 4]
#如果不想L1變化了L2也要跟着變化,需要Python拷貝對象,而不是創建引用。有很多種拷貝一個列表的辦法,包括內置列表函數以及標准庫的copy模塊。上面的方式是一種從頭到尾的分片方法。這里L1的修改不會影響L2,因為L2引用的是L1所引用對象的一個拷貝。也就是說,兩個變量指向了不同的內存區域。
#注意這種分片技術不會應用在其他的可變的核心類型(字典和集合,因為它們不是序列)上,復制一個字典或集合應該使用X.copy()方法調用。而且,注意標准庫中的copy模塊有一個通用的復制任意對象類型的調用,也有一個拷貝嵌套對象結構(例如,嵌套了一個列表的字典)的調用:
>>> L1=[1,2,3] >>> import copy >>> X = copy.copy(L1) #淺copy >>> X = copy.deepcopy(L1) #深copy