成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

python中的數(shù)據(jù)類型(list,tuple,dict,set,None)

NikoManiac / 1345人閱讀

摘要:數(shù)據(jù)類型變量用來存儲值,值可以被改變。數(shù)據(jù)的類型是各種各樣的,在小節(jié)中我們已經(jīng)看到非常普遍的數(shù)據(jù)類型數(shù)字,布爾值,字符串。在中有個內(nèi)置函數(shù),可以通過它來檢查一個對象的類型上面交互命令行中出現(xiàn)了四種簡單的數(shù)據(jù)類型,分別是,,,。

該系列文章:

《python入門,編程基礎(chǔ)概念介紹(變量,條件,函數(shù),循環(huán))》

《python中的數(shù)據(jù)類型(list,tuple,dict,set,None)》

《在python中創(chuàng)建對象(object)》

1.背景知識 1.1.簡化版python解釋器如何運行源代碼

python解釋器主要包含了兩大部分,一個部分相當于編譯器,另一個部分相當于虛擬機。python解釋器的編譯器部分首先把程序編譯成中間碼(字節(jié)碼),再由python解釋器里的虛擬機部分(Python Virtual Machine (PVM))運行字節(jié)碼。

1.2.簡化版對象(object)與類(class)

我們知道,給函數(shù)提供輸入(input),則函數(shù)會處理輸入(input),返回結(jié)果(output)或者不返回。程序就是解決問題的一系列步驟,這被稱為面向過程(Procedure Oriented) 的編程方式。后來,編程語言中出現(xiàn)了一種 面向?qū)ο螅∣bject Orientend) 的思想,簡單來說,對象借鑒了現(xiàn)實世界由一個個客體組成的概念,用一個個對象間的互動來組織起程序,跟現(xiàn)實世界的客體類似,對象有自己的特征(對象里的各種值),對象也有自己能夠做到的事(通過對象里的各種方法)。對象里的各種值被叫做對象的字段(field) ,對象里的各種方法被叫做對象的方法(method) ,對象的字段跟方法統(tǒng)稱為對象的屬性(attribute) 。

對象的字段類似于編程語言里的普通變量,所不同的是對象的字段是對象獨有的。如果一個對象叫a,a有個屬性是b,我們?nèi)绾卧L問b呢?答案是通過a.b這種形式的寫法訪問。a.b的意思就是a的屬性b。

對象的方法類似于編程語言中的函數(shù),所不同的是對象的方法是對象獨有的,如果一個對象叫c,c有個方法是d,我們?nèi)绾问褂茫ㄕ{(diào)用)d呢?答案是通過c.d()這種形式的寫法來是使用,d方法可以帶參數(shù),形如這樣:c.d(a)。c.d()的意思就是使用(調(diào)用)c的方法d。

如何實現(xiàn)對象呢?有一種方法就是通過類(class)來實現(xiàn)。對象對應(yīng)于現(xiàn)實中一個個具體的客體,這些客體各不相同,但是很明顯,有一些客體是可以歸到同一個陣營里去的,比如所有的人,所有的蘋果,所有的貓,這里的人、蘋果、貓是抽象的一般概念,程序中的類(class) 就是基于像這樣的一般概念而抽象出來的某一類客體的模板,可以是人的類,蘋果的類,貓的類。從類(模板)中可以構(gòu)造出這一類客體的對象。從類到對象,相當于從藍圖中實現(xiàn)了一個對象,所以可以說某對象是某個類的一個實例(實現(xiàn)了的例子)。反過來,某個類規(guī)定了將要實現(xiàn)的對象的該有的屬性跟方法,跟別的類實現(xiàn)的對象有了區(qū)別,所以對象的類型(type) 就是它所承襲的類。

1.3.簡化版調(diào)用棧(call stack),堆(heap)

內(nèi)存(memory):是指計算中的隨機存取內(nèi)存(random access memory (RAM))??梢哉J為,內(nèi)存是一張很大的表,其中的每個表格(1個字節(jié))有兩個屬性:地址和值。地址表示了某個表格在內(nèi)存這張大表中的位置,因此我們可以通過地址找到該表格;一旦找到該表格,就可以對該表格的值進行擦除并重寫的操作,或者只是讀取該表格的值。具體的細節(jié)我們可以不用去考慮,我們需要更加抽象的思考地址和值,任意大小的一塊內(nèi)存都可以有一個(標識)地址來讓我們在整個內(nèi)存中找到它,該內(nèi)存塊中能存儲復(fù)雜的值。

程序要運行時,操作系統(tǒng)就會給它分配一塊可用的內(nèi)存,或者由某高級語言虛擬機提供運行時環(huán)境。在該內(nèi)存空間(運行時環(huán)境)里,首先會載入程序本身(機器碼或者字節(jié)碼),接下來會載入整個程序可以用的東西(全局(類)變量,模塊等),除此之外的內(nèi)存會劃分為兩種,一種是程序運行時的調(diào)用棧(call stack),另一種則是堆(heap)。在這里,內(nèi)存并非計算機中真實的物理內(nèi)存,而是由操作系統(tǒng)通過軟硬件結(jié)合的一種技術(shù)分配的一塊虛擬內(nèi)存,該虛擬內(nèi)存中的虛擬地址跟計算機中真實的物理內(nèi)存地址之間有著映射的關(guān)系。在這樣的虛擬內(nèi)存空間里,地址是連續(xù)的,也就是說程序運行在某一塊特定的虛擬內(nèi)存中,可以想象成一個長塊兒。

當程序運行時,主函數(shù)(main函數(shù))或者首先被執(zhí)行的函數(shù)(方法)會被放入到調(diào)用棧中,因為調(diào)用棧中只有這一幀,所以它處在調(diào)用棧的頂層,一旦處在調(diào)用棧的頂層,就會被激活,被激活的幀(frame)得到程序的執(zhí)行權(quán),該幀中的代碼被一步步執(zhí)行,我們把這一幀姑且叫第0幀吧。第0幀中調(diào)用另一個函數(shù)(方法)時,被調(diào)用函數(shù)(方法)的幀被放入到調(diào)用棧的最頂層,我們把這一幀叫第1幀,現(xiàn)在,被激活的幀就變成了第1幀,程序的執(zhí)行權(quán)轉(zhuǎn)移到第1幀中,它首先會把被調(diào)用時傳進來的參數(shù)(如果有)存儲,接著就聲明和初始化局部(實例)變量,操作變量……當第1幀調(diào)用另一個函數(shù)(方法)時,被調(diào)用函數(shù)(方法)的幀被放入到調(diào)用棧的最頂層,我們把這一幀叫第2幀,如前所述,第2幀被激活,得到程序執(zhí)行權(quán),當第2幀執(zhí)行結(jié)束,返回值(如果有),這時候第2幀的內(nèi)存被銷毀,包括其中的局部(實例)變量、參數(shù)等等,第2幀在調(diào)用棧中不在存在,這時候,第1幀成為調(diào)用棧的頂層,程序的執(zhí)行權(quán)又重新回到第1幀,第1幀繼續(xù)執(zhí)行剩余的代碼,當第1幀執(zhí)行結(jié)束,返回值(如果有),第1幀被銷毀,調(diào)用棧中最頂層的幀重新變成第0幀,如果第0幀執(zhí)行結(jié)束,則調(diào)用??瞻住@其中,被調(diào)用函數(shù)(方法)放入調(diào)用棧最頂層被稱為推入(push),而在調(diào)用棧中被銷毀則被稱為彈出(pop)。

調(diào)用棧(call stack)中的函數(shù)(方法)里存儲著程序運行過程中該如何做的行為(動作、指令)和需要處理的局部(實例)變量,這些變量實際上是怎么被存儲的呢?不同的編程語言有不同的存儲方式,實際上有兩種最為主流的做法。

我們從上篇文章《python入門,編程基礎(chǔ)概念介紹(變量,條件,函數(shù),循環(huán))》已經(jīng)知道,變量的值有各種各樣的類型。像簡單的數(shù)字,布爾值,字符串……,對于這些比較簡單的值,一種方法就是把它們看做原始(內(nèi)置)類型,直接在調(diào)用棧內(nèi)存中分配出一塊能容納該類型值的內(nèi)存,把該值存進去,通過變量名來使用該值。這時候變量仿佛就是這些值了。這種存儲類型又被稱為值類型(value type)。需要注意的是,靜態(tài)類型語言中的變量是有類型的,一旦聲明成某種類型的,則只能存儲該類型的值;動態(tài)類型語言中的變量不存在類型,可以存儲任何類型的值。

對于簡單的數(shù)字,布爾值,字符串……這些類型的值,另一種方法就是把它們都存在堆(heap)內(nèi)存空間里。在調(diào)用棧中的變量里,實際存儲的是堆(heap)內(nèi)存空間里的某一塊內(nèi)存的地址。當一個變量被聲明并且被賦值的時候發(fā)生了什么呢?實際上發(fā)生的是首先在堆(heap)內(nèi)存空間中分配出一塊能容納該類型值的內(nèi)存,把該值存進去;然后把該內(nèi)存的地址綁定到變量上。這時候我們就說該變量引用(reference) 了該值。這種存儲類型被稱為引用類型(reference type)。有時候也能夠看到這種說法:變量里存儲的是值的引用,可以看到,值的內(nèi)存地址跟值的引用的說法可以互換。

前面我們簡略介紹了對象,對象可以看做是種復(fù)雜類型的值,你可以想想,對象里的各種屬性和各種方法。那么當我們有一個對象的時候,或者有某個復(fù)雜類型的值的時候,不同的編程語言都不約而同的選擇了堆(heap)內(nèi)存空間。這是為什么呢?因為調(diào)用棧中的值需要的內(nèi)存塊的大小一旦確定就不能改變,而堆則沒有這個限制,有可能一個對象占用很大的一塊內(nèi)存,并且在程序運行過程中動態(tài)的變大或者變小。

2.數(shù)據(jù)類型

變量用來存儲值,值可以被改變。正如我們之前好幾次說到的那樣,值的類型各種各樣,但都攜帶了某種信息,并且這種信息可以被操作(處理),我們可以認為,它們都是數(shù)據(jù)(data)。

數(shù)據(jù)的類型(type) 是各種各樣的,在1.3小節(jié)中我們已經(jīng)看到非常普遍的數(shù)據(jù)類型:數(shù)字,布爾值,字符串。對這些簡單的數(shù)據(jù)類型,我們已經(jīng)知道普遍存在的兩種存儲方式,那么在python中呢?在python中,一切數(shù)據(jù)類型都是對象,所以,我們存儲任何數(shù)據(jù)類型的方式都是通過引用(reference) 。

在python中有個內(nèi)置函數(shù)type(),可以通過它來檢查一個對象的類型:

>>> type(1)

>>> type(1.1)

>>> type("int")

>>> type(True)

>>> 

上面交互命令行中出現(xiàn)了四種簡單的數(shù)據(jù)類型,分別是int,float,str,bool。如果兩個變量同時引用了相同的對象,會發(fā)生什么呢?在python中有個內(nèi)置的函數(shù)id(),這個函數(shù)返回對象的一個id,可以把該id看做該對象的引用(內(nèi)存地址)。讓我們看看兩個變量同時引用相同的對象時發(fā)生了什么:

>>> a=1
>>> b=1
>>> id(a)
255681632
>>> id(b)
255681632
>>> 

可以看到,兩個變量指向了同一個對象,那么當我們改變了其中某個變量引用的對象,是不是另一個變量引用的對象也同時改變了呢?從理論上講會改變,對吧,因為是同一個對象。我們來看看:

>>> a=1
>>> b=1
>>> id(a)
255681632
>>> id(b)
255681632
>>> b=2 #改變b的值
>>> a
1
>>>

事實并不像我們認為的那樣,另一個變量的對象并沒有改變。這是因為,在python中,上面出現(xiàn)的這四種簡單的數(shù)據(jù)類型都是不可變(immutable) 對象。舉個數(shù)字的例子來理解這種不可變性:數(shù)字1是個對象,是個獨立的客體,看起來這個對象簡單到不能再簡單,我們無法改變它,如果將變量的引用從數(shù)字1改變成數(shù)字2,那么,已經(jīng)是另一個對象了,相當于是更新了變量的引用。

2.1.列表(list)

直到現(xiàn)在,我們處理過的數(shù)據(jù)類型都很簡單,但是當我們想要存儲更為復(fù)雜多變的數(shù)據(jù),用我們目前知道的數(shù)據(jù)類型來存儲就會越來越繁瑣,容易出錯了。比如我們想要在程序里一次性處理包含6個數(shù)字的內(nèi)容(7,9,11,36,74,12),難道我們要給每個數(shù)字都提供一個變量名,并一一存儲嗎?我們還有更多選擇,在python中,它提供了一種叫列表(list) 的數(shù)據(jù)類型,這種數(shù)據(jù)類型像個容器,可以裝進去其他各種數(shù)據(jù)類型,甚至也可以將其他列表(list)嵌套進去。我們要把7,9,11,36,74,12放進一個列表(list)中,可以這么做:

#把這幾個數(shù)字放進列表,并賦值給變量x
x=[7,9,11,36,74,12]  
#可以定義一個空列表
y=[]
#使用內(nèi)置函數(shù)list()創(chuàng)建列表
a=list("abc")
b=list()

現(xiàn)在把數(shù)字放進一個列表了,那么我們怎么拿出某個數(shù)字呢?跟字符串類似,列表中的元素組成了一串,每個元素在列表中都是有順序的。每個元素都被分配了一個位置索引(index)。我們可以通過特定的索引來訪問對應(yīng)的元素,根據(jù)慣例,索引總是從0開始。

x=[7,9,11,36,74,12]
z=len(x)
#從列表x中循環(huán)取出數(shù)字,并打印到命令行
for index in range(z):
    print(str(x[index]))

列表中的元素的值能不能改變呢?能不能增加或者減少元素?答案是可以的。我們說python中一切數(shù)據(jù)類型都是對象,列表也是對象,所有它有自己的專屬方法??梢酝ㄟ^列表的append()方法來增加元素,增加的元素被追加到列表結(jié)尾。刪除一個元素呢,可以通過del語句來刪除,也可以通過列表的remove()方法或者pop()方法來刪除。這里要注意,remove方法通過值來刪除,pop方法通過索引來刪除,并且remove方法沒有返回值,而pop方法則返回要刪除的值。如果我們不只想刪除某一個元素,而是想清空整個列表,則可以使用列表的clear()方法??聪旅妫?/p>

a=["change me",["first",1,2],2019,True]
#以下注釋都根據(jù)慣例,從0開始計數(shù)
#改變第0個元素的值
a[0]="changed"
print("列表a: {}".format(a))
#改變第1個元素(list)中的第0個元素
a[1][0]=0
print("列表a: {}".format(a))
#增加一個元素
a.append(2019)
print("列表a: {}".format(a))
#刪除一個元素,通過del語句
del a[0]
print("列表a: {}".format(a))
#刪除一個元素,通過remove方法
a.remove(True)
print("列表a: {}".format(a))
#刪除一個元素,通過pop方法,并將返回值賦給變量b
b=a.pop(2)
print("被刪除的元素是{}".format(b))
print("列表a: {}".format(a))
#清空列表
a.clear()
print("列表a: {}".format(a))

以上代碼中,用到了str的format()方法,這種方法通過在字符串保留一對{},來讓format方法中的參數(shù)填充其中,參數(shù)可以是任意多個(需要與前面{}的數(shù)量一致),可以是各種數(shù)據(jù)類型。這個方法大大簡化了我們想把其他數(shù)據(jù)類型加入到字符串的過程。運行結(jié)果如下:

列表a: ["changed", ["first", 1, 2], 2019, True]
列表a: ["changed", [0, 1, 2], 2019, True]
列表a: ["changed", [0, 1, 2], 2019, True, 2019]
列表a: [[0, 1, 2], 2019, True, 2019]
列表a: [[0, 1, 2], 2019, 2019]
被刪除的元素是2019
列表a: [[0, 1, 2], 2019]
列表a: []

既然python中的數(shù)據(jù)類型都是對象,那么我們?nèi)绾闻袛鄡蓚€對象是否是同一個呢。答案用is操作符。比如我們想要判斷a對象與b對象是否同一,則可以通過a is b來判斷,其結(jié)果是布爾值。

我們看到,列表里的元素可以比一個多,字符串里的字符也可以比一個多,所以我們給這種其中的元素或者屬性可以比一個多的對象運用in操作符(查看某元素是否屬于該對象,這被稱為成員檢測),來提供給for循環(huán)語句或者別的語句,讓這些語句逐個訪問其中的元素或者屬性,這個行為可以稱為迭代。前面說到的內(nèi)置函數(shù)list()可接受的參數(shù)就是可以被迭代的對象。上篇文章中講到的for...in循環(huán)就是迭代的一個例子。

#in操作符的例子
>>> x="hello"
>>> "h" in x
True
>>>

在講列表(list)之前,我們說到了不可變對象。那么列表的情況又是如何呢?我們把那個例子中的數(shù)據(jù)類型換成列表來看看:

a=["change me",["first",1,2],2019,True]
#把同樣的引用賦值給變量b
b=a
#看看引用是否相同,是否對象是同一個
print(a is b)
#通過變量b改變列表
b[0]="changed"
#現(xiàn)在打印出變量a,看是否有變化
print(a)

以上代碼運行結(jié)果如下:

True
["changed", ["first", 1, 2], 2019, True]

從運行結(jié)果來看,列表是可以改變的,所以是可變(mutable)對象?,F(xiàn)在我們已經(jīng)把可變對象不可變對象的行為差不多摸清楚了。講不可變對象的時候我們講解了一個數(shù)字對象的例子來幫助理解不可變對象,現(xiàn)在我們來通過字符串的例子來進一步說明,假如我們把一個字符串“string”的引用賦值給變量a,那么我們是不能對其中的字符來進行修改的,如下圖:

>>> a="string"
>>> a[0]="a"
Traceback (most recent call last):
  File "", line 1, in 
TypeError: "str" object does not support item assignment

但是對于變量a來說,它是完全可以更新的,可以把另一個對象的引用重新賦值給它:

>>> a="string"
>>> a[0]="a"
Traceback (most recent call last):
  File "", line 1, in 
TypeError: "str" object does not support item assignment
>>> a="hello"
>>> a
"hello"
>>>

事實上不可變對象無論是看著無法改變的,還是直覺上感覺可以改變的(比如字符串),都是python中規(guī)定好了的。所以不必糾結(jié)于直覺,我們要做的是記住哪些數(shù)據(jù)類型是可變的,而哪些數(shù)據(jù)類型又是不可變的。下面將介紹一種新的數(shù)據(jù)類型,它跟列表類似,最大的不同是,它是不可變的。它叫元組(tuple)。

2.2.元組(tuple)

元組(tuple) 中可以裝進去其他各種數(shù)據(jù)類型,甚至也可以將其他元組(tuple)嵌套進去。元組(tuple)的元素有索引(index),可以通過索引訪問到。

#空元組
tuple1=()
#一個元素的tuple,寫法特殊一點。如果在元素后面不加逗號
#則python解釋器會當成元素的數(shù)據(jù)類型,而不認為是個元組
tuple2=(2,)
#另一個元組,它里面有個列表作為元素
tuple3=(2,"lalala",True,45,[4,5])
#使用內(nèi)置函數(shù)tuple()創(chuàng)建元組,該函參數(shù)接受可迭代的對象
a=tuple()
b=tuple([1,2,3])

因為元組是不可變對象,所以它其中的元素是不能修改的。元素也不能增刪。但整個元組是可以通過del語句刪除的。但是當元組中的元素是可變對象時,比如元組中的某個元素是列表,那該列表能不能修改?因為該列表是可變對象,所以該列表中的元素是可以自然增刪修改的,但該列表因為是不可變對象中的元素,所以無法刪除,如下:

>>> d=(2, "lalala", True, 45, [5, 5])
>>> d[4][0]=88
>>> print(d)
(2, "lalala", True, 45, [88, 5])
>>> del d[4]
Traceback (most recent call last):
  File "", line 1, in 
TypeError: "tuple" object doesn"t support item deletion
>>> del d[4][0]
>>> print(d)
(2, "lalala", True, 45, [5])
>>>

那么情況反過來呢?當可變對象中的元素是不可變對象時,比如當列表中的某元素是個元組,該元組是否能夠被修改?因為該元組是不可變對象,所以該元組中的元素不能被修改,但是該元組本身是可變對象的元素,所以可以被刪除,如下:

>>> e=["he!",0,(4,5,"last")]
>>> e[2][0]=5
Traceback (most recent call last):
  File "", line 1, in 
TypeError: "tuple" object does not support item assignment
>>> del e[2][0]
Traceback (most recent call last):
  File "", line 1, in 
TypeError: "tuple" object doesn"t support item deletion
>>> del e[2]
>>> print(e)
["he!", 0]
>>>
2.3.序列(sequence)

一個數(shù)據(jù)集合里面的元素根據(jù)放入的先后順序排成一串,這種形式的數(shù)據(jù)可以被稱為序列。字符串,列表,元組都有著類似序列的結(jié)構(gòu),所以也就有類似的行為,它們都可以被索引,都可以被迭代,都能夠通過索引訪問到其中的元素;不僅僅是能夠訪問到其中的某一個元素,還能訪問到其中的某幾個元素,這種同時訪問到好幾個元素的行為,稱為切片(也可以把被訪問的這些元素稱為數(shù)據(jù)的切片),因為這樣做相當于從整個數(shù)據(jù)序列中切下來一部分,如下:

x="string"
y=[1,2,3,4,5,6]
z=(7,8,9,10,11,12)
#以下注釋都根據(jù)慣例,從0開始計數(shù)
#打印出字符串的第3個字符
print(x[3])
#打印出字符串的倒數(shù)第2個字符
print(x[-2])
#打印出字符串的一部分,從第1個開始,到第3個字符,不包括第4個字符
print(x[1:4])
#打印出列表的倒數(shù)第3個元素
print(str(y[-3]))
#打印出列表的一部分,從第1個元素開始,到第4個元素,不包括第5個元素
print(str(y[1:5]))
#打印出列表的一部分,從第1個元素開始,直到結(jié)束
print(str(y[1:]))
#打印出元組的倒數(shù)第4個元素
print(str(z[-4]))
#打印出元組的一部分,從第1個元素開始,到第4個元素,不包括第5個元素
print(str(z[1:5]))
#打印出列表的一部分,從第1個元素開始,直到結(jié)束
print(str(z[1:]))

運行如下:

i
n
tri
4
[2, 3, 4, 5]
[2, 3, 4, 5, 6]
9
(8, 9, 10, 11)
(8, 9, 10, 11, 12)

切片中可以設(shè)置步長,就是說可以設(shè)置隔著幾個元素的方式訪問數(shù)據(jù)的一部分,默認步長為1,如下:

>>> a=(1,2,3,4,5,6,7,8,9,10)
>>> a[::1]
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
>>> a[::2]
(1, 3, 5, 7, 9)
>>>

當我們把數(shù)據(jù)的切片賦值給變量時會發(fā)生什么?一般來說,數(shù)據(jù)被切片部分會被復(fù)制一份副本,然后把副本的引用賦值給變量。但是,有個特殊情況,就是當數(shù)據(jù)的被切片部分是全部數(shù)據(jù)本身時,那該數(shù)據(jù)要看是可變對象還是不可變對象了。列表(可變對象)則會復(fù)制一份副本,然后把副本的引用賦值給變量,而字符串、元組(不可變對象)則會直接將該數(shù)據(jù)本身的引用直接賦值給變量,如下:

>>> a=[1,2,3,4]
>>> b=a[:]  #省略掉開頭跟結(jié)尾index則切片結(jié)果是數(shù)據(jù)本身
>>> id(a)
140046385947272
>>> id(b)
140046386409992
>>> c=(1,2,[2,3])
>>> d=c[:]
>>> id(c)
140046385743768
>>> id(d)
140046385743768
>>> 
2.4.字典(dict)

前面我們介紹了序列,我們知道序列的索引隱含在數(shù)據(jù)類型里,不需要我們明確去定義,因為都是0,1,2,3,4……有順序的排列下去,當可變對象里的元素被刪除,保留下來的元素的索引會改變,因為序列里的索引永遠都是順序排列的數(shù)字,這些數(shù)字沒有跟元素綁定,而只是允許我們通過索引的數(shù)字來訪問該位置的元素。那如果我們想要自定義索引,用字符串,數(shù)字等來做索引,并希望這些索引能夠跟特定的元素綁定在一起,我們該怎么辦?更簡單的說,就是我們希望索引是獨特并且容易記住,有語義,我們該怎么辦?python給我們提供了一種數(shù)據(jù)類型字典(dict),可以勝任這樣的要求。我們把這樣的索引可以看作是鍵 (keys),它與要存儲的值綁定在一起,叫做鍵值對。

字典里存儲鍵值對兒,索引獨特,所以是沒有順序的。順序已經(jīng)無關(guān)緊要,我們只需要記住獨特的鍵就行了。如何創(chuàng)建字典,如何存儲鍵值對,看下面的例子:

>>> a={}    #創(chuàng)建一個空字典
>>> type(a)

>>> b={"id":4667,"name":"john"}  #創(chuàng)建一個有兩對鍵值對的字典
>>> b["id"]  #通過鍵"id"來獲得對應(yīng)的值
4667
>>> c=dict(id=4555,name="li")  #通過內(nèi)置的dict函數(shù)創(chuàng)建字典
>>> print(c)
{"id": 4555, "name": "li"}
>>> 

字典是可變對象。為了通過鍵來查找值,就需要字典鍵(keys)保持唯一性,如果鍵用了可變對象來存儲,會出現(xiàn)不可控因素,舉個例子,假如兩個鍵都是由列表來存儲,則一旦把這兩個列表修改相同,那么查找這兩個鍵所對應(yīng)的值時就會出現(xiàn)矛盾,所以鍵一定要用不可變對象來存儲,包括數(shù)字,布爾值,字符串,元組(需要元組中的元素不包含可變對象)。又因為字典是可變對象,所以字典中鍵值對里的值是可以改變的。如下:

>>> c={("id",):46678,"name":"john_ss"}
>>> c[("id",)]
46678
>>> d=8
>>> e={d:8,"d":"8"}
>>> e[d]
8
>>> e["d"]
"8"
>>> e[d]=123
>>> print(e)
{8: 123, "d": "8"}
>>> 

在字典中,也可以用字典的get()方法通過鍵獲取值。如果要給字典里增加鍵值對,可以直接用方括號(下標)的方式增加,例如dict["key_word"]="some values"??梢杂米值涞膒op()方法來刪除鍵值對,要注意的是,pop()方法在刪除鍵值對的同時會返回要移除的鍵值對,把返回值賦給變量,變量就會得到被移除的鍵值對:pair=dict.pop("id")。如果我們不只想刪除某一個鍵值對,而是想清空整個字典,則可以使用字典的clear()方法。如果看下面的例子:

>>> a={1:1,2:2,3:3}
>>> a.get(1)
1
>>> a["appended"]="ok,then!"
>>> print(a)
{1: 1, 2: 2, 3: 3, "appended": "ok,then!"}
>>> a.pop(2)
2
>>> print(a)
{1: 1, 3: 3, "appended": "ok,then!"}
>>> a.clear()
>>> print(a)
{}
>>> 

當我們嘗試像迭代序列那樣直接迭代字典時,交互命令行顯示結(jié)果如下,明顯只迭代了鍵值對中的鍵(key):

>>> a={1: 1, 2: 2, 3: 3, "appended": "ok,then!"}
>>> for item in a:
...     print(item)
... 
1
2
3
appended
>>> 

這時候字典中有兩個內(nèi)置方法可以協(xié)助來完成迭代,分別是items()跟keys()。items()返回字典中無序的鍵值對,keys()返回字典中無序的鍵(keys)。如下:

>>> a={1: 1, 2: 2, 3: 3, "appended": "ok,then!"}
>>> for item in a.items():
...     print(item)
... 
(1, 1)   #可以看到把鍵值對裝進了元組
(2, 2)
(3, 3)
("appended", "ok,then!")
>>> for key in a.keys():
...     print(key)
... 
1
2
3
appended
>>> 
2.5.集合(set),frozenset

前面我們介紹了字典,跟字典類似,在python里還有一種無序的數(shù)據(jù)類型:集合(set)?;旧希@兒的集合跟數(shù)學(xué)上的集合的概念是一樣的。其中的元素是無序的,并且每個元素都是唯一不可重復(fù)的。創(chuàng)建集合跟創(chuàng)建字典的符號一樣,都是花括號“{}”,所以當創(chuàng)建空集合時,會跟創(chuàng)建空字典的符號有沖突,所以python里“{}”表示創(chuàng)建空字典,而創(chuàng)建空集合只能用內(nèi)置函數(shù)set()來創(chuàng)建,如下:

>>> a={1,4,7,"string",("lalala",2,3,4)}  #創(chuàng)建集合
>>> print(a)
{1, 4, 7, "string", ("lalala", 2, 3, 4)}
>>> b={}   #空字典
>>> type(b)

>>> c=set()  #空集合
>>> type(c)

>>> 

集合是可變對象,但是它的元素則要求一定是不可變對象,根據(jù)集合的定義,每個元素都是唯一不可重復(fù),那么一旦元素是可變對象,則有了可重復(fù)的可能,比如元素中有兩個列表的話,通過一些操作有可能會讓這兩個列表成為一樣的。如下:

>>> d={1,2,[1,2]}
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unhashable type: "list"
>>> 

既然集合是可變對象,我們就可以通過add()方法增加元素,通過remove()、discard()方法、pop()方法刪除元素,前提是所有元素都要是不同的,通過pop()方法刪除元素時,不帶參數(shù),并且集合無序,所以無法預(yù)知哪個元素被丟掉,但pop()方法會返回被丟的元素:

>>> a={1,4,7,("string",55),"hello"}
>>> a.add("hello,world!") #add方法新增元素
>>> print(a)
{1, 4, 7, "hello,world!", ("string", 55), "hello"}
>>> a.remove(7) #remove方法刪除元素
>>> print(a)
{1, 4, "hello,world!", ("string", 55), "hello"}
>>> a.discard(1) #discard方法刪除元素
>>> print(a)
{4, "hello,world!", ("string", 55), "hello"}
>>> a.pop()   #通過pop方法刪除隨機某個元素并返回被刪除的元素,可以使用變量來存儲
4
>>> print(a)
{"hello,world!", ("string", 55), "hello"}

可以使用update方法來增加多個元素,使用clear()方法來清空整個集合,接上面的例子:

>>> a.update([1,2,3,4])  #用列表來更新集合
>>> a.update((5,6,7))    #用元組來更新集合
>>> print(a)
{1, 2, 3, 4, 5, 6, 7, "hello,world!", ("string", 55), "hello"}
>>> a.clear()
>>> print(a)
set()   #代表空集合

集合可以實現(xiàn)數(shù)學(xué)上的并集,交集,差集,對稱差,有兩種方式:操作符跟方法。并集是兩個集合中所有的元素組成的新集合,交集是兩個集合中都存在的元素組成的新集合。差集是兩個集合中在某個集合中存在,并且在另一個集合中不存在的元素組成的新集合。對稱差集是兩個集合中所有元素,除去在交集中的元素,由這樣的元素組成的新集合。下面這個表顯示python的操作方法:

操作名稱 操作符 集合(比如A,B)內(nèi)置方法
| A.union(B)
& A.intersection(B)
- A.difference(B)
對稱差 ^ A.symmetric_difference(B)

通過例子來看看:

>>> A={1,2,4,6,7}
>>> B={1,3,4,5,8}
>>> print(A | B)
{1, 2, 3, 4, 5, 6, 7, 8}
>>> print(A.union(B))
{1, 2, 3, 4, 5, 6, 7, 8}
>>> print(A & B)
{1, 4}
>>> print(A.intersection(B))
{1, 4}
>>> print(A - B)
{2, 6, 7}
>>> print(A.difference(B))
{2, 6, 7}
>>> print(B - A)
{8, 3, 5}
>>> print(B.difference(A))
{8, 3, 5}
>>> print(A ^ B)
{2, 3, 5, 6, 7, 8}
>>> print(A.symmetric_difference(B))
{2, 3, 5, 6, 7, 8}
>>> 

從上面的例子可以看出來,兩個集合的并集,交集,對稱差集都是可以互換的,而差集不是,差集需要區(qū)分A-BB-A。

在python中,還可以創(chuàng)建類似于tuple這樣的不可變對象的set,那就是frozenset,frozen在英文中是凍結(jié)了的意思,顧名思義,frozenset就是凍結(jié)的集合。frozenset不能增加或者更新元素,刪除或者清除元素,類似于只讀文件。并集,交集,差集,對稱差的操作對于frozenset同樣適用。如下:

>>> a=frozenset([1,2,3])   #創(chuàng)建一個frozenset
>>> print(a)
frozenset({1, 2, 3})
>>> a.add(4)
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: "frozenset" object has no attribute "add"
>>> a.clear()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: "frozenset" object has no attribute "clear"
>>> b=frozenset((4,5,3))
>>> a.union(b)
frozenset({1, 2, 3, 4, 5})
>>> 
2.6.簡化內(nèi)置的help函數(shù),獲取python中各數(shù)據(jù)類型內(nèi)置的方法及其簡要說明

在python中,有個help()內(nèi)置函數(shù)可以獲取關(guān)于對象的說明文檔。但說明文檔中有關(guān)于該對象實現(xiàn)的細節(jié),當我們只是想知道各數(shù)據(jù)類型的常用內(nèi)置方法及其使用時,就會變得很不方便。我寫了一個很短的程序,運行該程序可以將help函數(shù)的輸出簡化(刪去實現(xiàn)對象的相關(guān)細節(jié))并存入當前目錄新建的一個文本文件中,并且該程序還有將方法的解釋翻譯成中文的可選功能。下面是該程序內(nèi)容:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import re
#如果想將解釋翻譯成中文,把下面一行的注釋取消
#from translate import Translator

def command_line_arguments(usge,len_of_arguments):
    if len(sys.argv)!=len_of_arguments+1:
        print(usge)
    return sys.argv

def stdout_to_file(dir,func,func_arguments):
    #把函數(shù)的標準輸出存入文件中
    default_stdout = sys.stdout
    with open(dir,"w") as w:
        sys.stdout=w
        func(func_arguments)
    sys.stdout=default_stdout
    
def simpler_help(object):
    
    stdout_to_file("simpler_help_{}.txt".format(object),help,object)
    
    #把文件中的內(nèi)容分行存入內(nèi)存
    with open("simpler_help_{}.txt".format(object),"r") as r:
        lines=r.readlines()
    
    #將內(nèi)存中的內(nèi)容修改后寫入同名文件,覆蓋原有文件
    #mark1,為了將帶有“__”的特殊函數(shù)不要寫入,并將其下面的解釋一并略過
    mark1=False
    #mark2,為了將“---”下面的內(nèi)容略過
    mark2=False
    with open("simpler_help_{}.txt".format(object),"w") as w:
        for line in lines:
            
            #將帶有“__”的特殊方法不要寫入,并將其下面的解釋一并略過
            if "__" in line:
                mark1=True
                continue  
            elif mark1==True:
                result=re.search("[A-Za-z]+",line)
                if result==None:
                    mark1=False
                    continue
                

            #將“---”下面的內(nèi)容略過
            elif "---" in line:
                mark2=True
                continue
            elif mark2==True:
                pass
            
            #將行中的self跟“/”替換成空
            else:
                if ("self," in line) or ("/" in line):
                    if ("self," in line) and ("/" in line):
                        w.write(line.replace("self,","").replace("/","").replace(", )"," )").replace(" , "," "))
                    elif ("self," in line) and ("/" not in line):
                        w.write(line.replace("self,",""))
                    elif ("self," not in line) and ("/" in line):
                        w.write(line.replace("/","").replace(", )"," )").replace(" , "," "))          
                else:
                    w.write(line)

#如果想將解釋翻譯成中文,可以把下面的函數(shù)注釋取消                
"""
def translation_of_help(object):
    translator= Translator(to_lang="zh")
    with open("simpler_help_{}_zh.txt".format(object),"r") as r:
        lines=r.readlines()
    with open("simpler_help_{}_zh.txt".format(object),"w") as w:
        line_process=""
        count_line=0
        for line in lines:
            if ("(" in line) and (")"in line) and ("." not in line):
                w.write(line)
            else:
                if count_line<=1:
                    w.write(translator.translate(line)+"
")
                else:
                    line_process=line.replace("|","")
                    w.write(" |        "+translator.translate(line_process)+"
")
            count_line=count_line+1
"""

len_of_arguments=1
arguments=command_line_arguments("""You need provide a name of object,for example:
python3 simpler_help.py list""",len_of_arguments)
if len(arguments)==len_of_arguments+1:
    simpler_help(arguments[1])
    #如果想將解釋翻譯成中文,可以把下面一行的注釋取消
    #translation_of_help("list")      
    

將上面內(nèi)容復(fù)制粘貼,并命名為simpler_help.py。舉個例子,如果想知道列表中的內(nèi)置方法,則在命令行中通過類似這樣的python3 simpler_help.py list命令來運行,特別注意需要在文件名空一格后寫上需要查詢的數(shù)據(jù)類型名稱。下面是程序創(chuàng)建的簡化版的列表的help函數(shù)輸出,保存在當前目錄的simpler_help_list.txt中:

Help on class list in module builtins:

class list(object)
 |  list(iterable=() )
 |  
 |  Built-in mutable sequence.
 |  
 |  If no argument is given, the constructor creates a new empty list.
 |  The argument must be an iterable if specified.
 |  
 |  Methods defined here:
 |  
 |  append( object )
 |      Append object to the end of the list.
 |  
 |  clear( )
 |      Remove all items from list.
 |  
 |  copy( )
 |      Return a shallow copy of the list.
 |  
 |  count( value )
 |      Return number of occurrences of value.
 |  
 |  extend( iterable )
 |      Extend list by appending elements from the iterable.
 |  
 |  index( value, start=0, stop=9223372036854775807 )
 |      Return first index of value.
 |      
 |      Raises ValueError if the value is not present.
 |  
 |  insert( index, object )
 |      Insert object before index.
 |  
 |  pop( index=-1 )
 |      Remove and return item at index (default last).
 |      
 |      Raises IndexError if list is empty or index is out of range.
 |  
 |  remove( value )
 |      Remove first occurrence of value.
 |      
 |      Raises ValueError if the value is not present.
 |  
 |  reverse( )
 |      Reverse *IN PLACE*.
 |  
 |  sort( *, key=None, reverse=False)
 |      Stable sort *IN PLACE*.
 | 
 

通過程序創(chuàng)建的文件,可以大概了解各數(shù)據(jù)類型都有哪些內(nèi)置方法,之后可以從網(wǎng)上通過關(guān)鍵詞搜索出更為詳細的介紹跟用例。另外,如果想將方法的解釋翻譯成中文,把simpler_help.py中相關(guān)內(nèi)容的注釋取消,并且首先需要在命令行中執(zhí)行pip install translate

2.7.關(guān)于None
>>> type(None)

>>>

None屬于NoneType這個數(shù)據(jù)類型(對象),是它唯一的值。并且,NoneType對象并不像別的數(shù)據(jù)類型一樣,可以有很多實例,而是從始至終都只能有一個實例。

>>> None==False
False
>>> None==1
False
>>> None==""
False
>>> None==0
False
>>> None=={}
False
>>> None==None
True
>>>

從上面的例子(做邏輯判斷)可以看出來,None不等于其他任何值,None只等于None。None一般用來代表數(shù)據(jù)的缺失,看下面的例子:

def addTwo(a,b):
    if (type(a)==int or type(a)==float) and ((type(b)==int or type(b)==float)):
        return a+b
    else:
        return None

b=addTwo("ss",4)
print(b)

#OUTPUT應(yīng)該為None,None代表函數(shù)沒法合理的處理參數(shù),只能返回None。

當我們拿到某個數(shù)據(jù),我們想要判斷它不是None的時候該如何做呢,這時候應(yīng)該用is,因為None是數(shù)據(jù)類型,也是對象,所以我們一般會想要這樣做:if an_object is not None:。此處not的位置跟成員檢測if an_object not in an_object:的位置不同,需要特別注意。如下:

a=1

if a is not None:
    print("a is not None")
else:
    print("a is None")

#OUTPUT應(yīng)該為"a is not None"。

有些時候我們會在別人的代碼中看到if an_object:這樣的寫法,這種寫法跟上面的判斷某數(shù)據(jù)(對象)是不是None的寫法沒有什么聯(lián)系,這種代碼暗示了數(shù)據(jù)(對象)本身在做邏輯判斷時會另外呈現(xiàn)出或真或假的布爾值,事實上也的確如此,在各種數(shù)據(jù)類型中,會有某些特殊的值在邏輯判斷的時候布爾值表現(xiàn)為False,其余值表現(xiàn)為True。在python中,規(guī)定了一套規(guī)則,當我們拿某個數(shù)據(jù)本身來做邏輯判斷的時候,解釋器如何解確定其布爾值:

布爾型,F(xiàn)alse表示False,其他為True

整數(shù)和浮點數(shù),0表示False,其他為True

字符串和類字符串類型(包括bytes和unicode),空字符串表示False,其他為True

序列類型(包括tuple,list,dict,set等),空表示False,非空表示True

None永遠表示False

舉個例子,當我們在理論上來說從某函數(shù)(方法)返回了一個列表list1,我們用if list1:來判斷的時候,則會出現(xiàn)三種情況:list1None,list1是空列表,list1是非空列表,這時候list1在第一和第二種情況下表現(xiàn)出的布爾值為False,在第三種情況下表現(xiàn)出的布爾值為True。如下:

list1=[]

while True:
    if list1:
        print("true")
    else:
        if list1 != None:
            print("false,empty list")
            list1=None
        else:
            print("false,None")
            list1=[]

#OUTPUT應(yīng)該永遠在None跟空列表之間徘徊。交替打印“false,empty list”和“false,None”。

[歡迎瀏覽我的個人博客,https://diwugebingren.github.io
](https://diwugebingren.github....

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/43950.html

相關(guān)文章

  • python中的listtuple,setdict(參考python文檔)

    摘要:聲明一個很簡單,只需盡量不要將變量名起為關(guān)鍵字。有如下基本方法在的末尾添加一個元素,并且返回將另一個的對象添加到尾部,返回值為。返回值為刪掉的元素。為一個表達式,傳入當前元素,返回時依據(jù)德關(guān)鍵字。 1.list 聲明一個list很簡單,只需list1=[](盡量不要將變量名起為關(guān)鍵字list)。list有如下基本方法: (1)append(x) 在list的末尾添加一個元素x,并且返回...

    NervosNetwork 評論0 收藏0
  • 3-python 元組 字典 集合的操作

    摘要:元組本質(zhì)是一種有序集合和相似元組是不可變的用創(chuàng)建其中類型可以不同如果一個元組中只有一個元素,在這個元素后面加一個逗號來消除歧義修改元組表面上看,的元素改變了,但實際上變得不是的元素,是的元素刪除被直接刪除數(shù)據(jù)類型轉(zhuǎn)換字典字典中的必須唯一值必 元組 tuple 本質(zhì)是一種有序集合 和list相似 元組是不可變的 用()創(chuàng)建 其中類型可以不同 如果一個元組中只有一個元素,在這個元素后面加...

    CKJOKER 評論0 收藏0
  • python學(xué)習(xí)筆記-數(shù)據(jù)集合: list,tuple,dict,set

    摘要:元素的獲取與一致,即即可。中的是唯一的不可變對象。若不存在該則返回。是一個有序且不重復(fù)的數(shù)據(jù)集合。創(chuàng)建創(chuàng)建時重復(fù)的元素將被自動刪除。添加元素刪除元素若元素不存在,則會報錯誤。 Python的數(shù)據(jù)集合有四種,即list,tuple,dict,set 列表,List List是Python中一種有序的可變的數(shù)據(jù)集合。它的元素可以被添加或則刪除。List的表示方法是用一個[]將元素包含起來,...

    qylost 評論0 收藏0
  • Python筆記

    摘要:精簡,快速,并持續(xù)完善。布爾類型一個布爾值只有兩種值,可以用和運算中的從左到右計算表達式,若所有值均為真,則返回最后一個值,若存在假,返回第一個假值。浮點型在運算中,整數(shù)與浮點數(shù)運算的結(jié)果是浮點數(shù)。 精簡,快速,并持續(xù)完善。 輸入與輸出 >>> print(Name: %s, score: %d % (Jack, 89)) Name: Jack, score: 89 >>> prin...

    nifhlheimr 評論0 收藏0
  • 記錄我的Python學(xué)習(xí)筆記

    摘要:本文是通過廖雪峰的網(wǎng)站學(xué)習(xí)而整理的真的是很好的教程,省得我花錢買書了,然后我沒有去再整理總結(jié)語法,而是直接通過寫出代碼段來體現(xiàn)自己的學(xué)習(xí),也方便以后的快速復(fù)習(xí)回顧。 不想再像以前那樣,什么都從頭開始學(xué)習(xí)語法、總結(jié)語法,這樣反而會過分糾結(jié)于語法,耽誤了開發(fā),畢竟語言的主要屬性是工具,次要的屬性是語言本身。 所以還是先熟練使用語言去進行開發(fā),等足夠熟悉了,再去研究語言本身(編譯原理……)。...

    lijy91 評論0 收藏0
  • [Python]容器類變量的使用學(xué)習(xí)

    摘要:的強大之處在于數(shù)據(jù)操作的方便和大類的第三方本文主要是學(xué)習(xí)收集數(shù)據(jù)操作相關(guān)的內(nèi)容相關(guān)內(nèi)容通過代碼對基本內(nèi)容進行學(xué)習(xí)這是一個空的注意這不是一個變量,而是一個類型的變量注意與上面的例子對比,這里在括號內(nèi)加了一個逗號,變量類型為變量包含多個元素,元 0:Python的強大之處在于數(shù)據(jù)操作的方便和大類的第三方module,本文主要是學(xué)習(xí)收集數(shù)據(jù)操作相關(guān)的內(nèi)容 1:Tuple相關(guān)內(nèi)容 #通過代碼對...

    李增田 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<