在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 字典(2)
標(biāo)準(zhǔn)庫 (4)
如何成為 Python 高手
標(biāo)準(zhǔn)庫 (6)
標(biāo)準(zhǔn)庫 (3)
類(2)
Pandas 使用 (2)
xml
用 tornado 做網(wǎng)站 (5)
文件(1)
練習(xí)
列表(3)
從小工到專家
除法
錯誤和異常 (2)
函數(shù)(1)
用 tornado 做網(wǎng)站 (7)
為做網(wǎng)站而準(zhǔn)備
函數(shù)練習(xí)
標(biāo)準(zhǔn)庫 (8)
Pandas 使用 (1)
回顧 list 和 str
字典(1)
用 tornado 做網(wǎng)站 (3)
字符串(1)
函數(shù)(2)
寫一個簡單的程序
將數(shù)據(jù)存入文件
語句(5)
SQLite 數(shù)據(jù)庫
集成開發(fā)環(huán)境(IDE)
集合(1)
類(1)
用 tornado 做網(wǎng)站 (6)
用 tornado 做網(wǎng)站 (2)
自省
語句(4)
錯誤和異常 (1)
用 tornado 做網(wǎng)站 (4)
集合(2)
列表(1)
標(biāo)準(zhǔn)庫 (1)
生成器
mysql 數(shù)據(jù)庫 (1)
第三方庫
實戰(zhàn)
運算符
類(3)
字典(2)
語句(1)
數(shù)和四則運算
語句(2)
文件(2)
MySQL 數(shù)據(jù)庫 (2)
電子表格
迭代器
mongodb 數(shù)據(jù)庫 (1)
特殊方法 (2)
特殊方法 (1)
字符編碼
編寫模塊
用 tornado 做網(wǎng)站 (1)
標(biāo)準(zhǔn)庫 (5)
函數(shù)(4)
類(5)
字符串(2)
關(guān)于 Python 的故事
函數(shù)(3)
字符串(4)
處理股票數(shù)據(jù)
常用數(shù)學(xué)函數(shù)和運算優(yōu)先級
字符串(3)
為計算做準(zhǔn)備
多態(tài)和封裝
類(4)
迭代
語句(3)
錯誤和異常 (3)
分析 Hello
Python 安裝
標(biāo)準(zhǔn)庫 (2)
列表(2)
元組

字典(2)

字典方法

跟前面所講述的其它數(shù)據(jù)類型類似,字典也有一些方法。通過這些方法,能夠?qū)崿F(xiàn)對字典類型數(shù)據(jù)的操作。這回可不是屠龍之技的。這些方法在編程實踐中經(jīng)常會用到。

copy

拷貝,這個漢語是 copy 的音譯,標(biāo)準(zhǔn)的漢語翻譯是“復(fù)制”。我還記得當(dāng)初在學(xué) DOS 的時候,那個老師說“拷貝”,搞得我暈頭轉(zhuǎn)向,他沒有說英文的“copy”發(fā)音,而是用標(biāo)準(zhǔn)漢語說“kao(三聲)bei(四聲)”,對于一直學(xué)習(xí)過英語、標(biāo)準(zhǔn)漢語和我家鄉(xiāng)方言的人來說,理解“拷貝”是有點困難的。誰知道在編程界用的是音譯呢。

在一般的理解中,copy 就是將原來的東西再搞一份。但是,在 Python 里面(乃至于很多編程語言中),copy 可不是那么簡單的。

>>> a = 5
>>> b = a
>>> b
5

這樣做,是不是就得到了兩個 5 了呢?表面上看似乎是,但是,不要忘記我在前面反復(fù)提到的:對象有類型,變量無類型,正是因著這句話,變量其實是一個標(biāo)簽。不妨請出法寶:id(),專門查看內(nèi)存中對象編號

>>> id(a)
139774080
>>> id(b)
139774080

果然,并沒有兩個 5,就一個,只不過是貼了兩張標(biāo)簽而已。這種現(xiàn)象普遍存在于 Python 的多種數(shù)據(jù)類型中。其它的就不演示了,就僅看看 dict 類型。

>>> ad = {"name":"qiwsir", "lang":"Python"}
>>> bd = ad
>>> bd
{'lang': 'Python', 'name': 'qiwsir'}
>>> id(ad)
3072239652L
>>> id(bd)
3072239652L

是的,驗證了。的確是一個對象貼了兩個標(biāo)簽。這是用賦值的方式,實現(xiàn)的所謂“假裝拷貝”。那么如果用 copy 方法呢?

>>> cd = ad.copy()
>>> cd
{'lang': 'Python', 'name': 'qiwsir'}
>>> id(cd)
3072239788L

果然不同,這次得到的 cd 是跟原來的 ad 不同的,它在內(nèi)存中另辟了一個空間。如果我嘗試修改 cd,就應(yīng)該對原來的 ad 不會造成任何影響。

>>> cd["name"] = "itdiffer.com"
>>> cd 
{'lang': 'Python', 'name': 'itdiffer.com'}
>>> ad
{'lang': 'Python', 'name': 'qiwsir'}

真的是那樣,跟推理一模一樣。所以,要理解了“變量”是對象的標(biāo)簽,對象有類型而變量無類型,就能正確推斷出 Python 能夠提供的結(jié)果。

>>> bd
{'lang': 'Python', 'name': 'qiwsir'}
>>> bd["name"] = "laoqi"
>>> ad
{'lang': 'Python', 'name': 'laoqi'}
>>> bd
{'lang': 'Python', 'name': 'laoqi'}

這是又修改了 bd 所對應(yīng)的“對象”,結(jié)果發(fā)現(xiàn) ad 的“對象”也變了。

然而,事情沒有那么簡單,看下面的,要仔細(xì)點,否則就迷茫了。

>>> x = {"name":"qiwsir", "lang":["Python", "java", "c"]}
>>> y = x.copy()
>>> y
{'lang': ['Python', 'java', 'c'], 'name': 'qiwsir'}
>>> id(x)
3072241012L
>>> id(y)
3072241284L

y 是從 x 拷貝過來的,兩個在內(nèi)存中是不同的對象。

>>> y["lang"].remove("c")

為了便于理解,盡量使用短句子,避免用很長很長的復(fù)合句。在 y 所對應(yīng)的 dict 對象中,鍵"lang"的值是一個列表,為['Python', 'java', 'c'],這里用 remove()這個列表方法刪除其中的一個元素"c"。刪除之后,這個列表變?yōu)椋篬'Python', 'java']

>>> y
{'lang': ['Python', 'java'], 'name': 'qiwsir'}

果然不出所料。那么,那個x所對應(yīng)的字典中,這個列表變化了嗎?應(yīng)該沒有變化。因為按照前面所講的,它是另外一個對象,兩個互不干擾。

>>> x
{'lang': ['Python', 'java'], 'name': 'qiwsir'}

是不是有點出乎意料呢?我沒有作弊哦。你如果不信,就按照操作自己在交互模式中試試,是不是能夠得到這個結(jié)果呢?這是為什么?

但是,如果要操作另外一個鍵值對:

>>> y["name"] = "laoqi"
>>> y
{'lang': ['python', 'java'], 'name': 'laoqi'}
>>> x
{'lang': ['python', 'java'], 'name': 'qiwsir'}

前面所說的原理是有效的,為什么到值是列表的時候就不奏效了呢?

要破解這個迷局還得用 id()

>>> id(x)
3072241012L
>>> id(y)
3072241284L

x,y 對應(yīng)著兩個不同對象,的確如此。但這個對象(字典)是由兩個鍵值對組成的。其中一個鍵的值是列表。

>>> id(x["lang"])
3072243276L
>>> id(y["lang"])
3072243276L

發(fā)現(xiàn)了這樣一個事實,列表是同一個對象。

但是,作為字符串為值得那個鍵值對,是分屬不同對象。

>>> id(x["name"])
3072245184L
>>> id(y["name"])
3072245408L

這個事實,就說明了為什么修改一個列表,另外一個也跟著修改;而修改一個的字符串,另外一個不跟隨的原因了。

但是,似乎還沒有解開深層的原因。深層的原因,這跟 Python 存儲的數(shù)據(jù)類型特點有關(guān),Python 只存儲基本類型的數(shù)據(jù),比如 int,str,對于不是基礎(chǔ)類型的,比如剛才字典的值是列表,Python 不會在被復(fù)制的那個對象中重新存儲,而是用引用的方式,指向原來的值。如果讀者沒有明白這句話的意思,我就只能說點通俗的了(我本來不想說通俗的,裝著自己有學(xué)問),Python 在所執(zhí)行的復(fù)制動作中,如果是基本類型的數(shù)據(jù),就在內(nèi)存中重新建個窩,如果不是基本類型的,就不新建窩了,而是用標(biāo)簽引用原來的窩。這也好理解,如果比較簡單,隨便建立新窩簡單;但是,如果對象太復(fù)雜了,就別費勁了,還是引用一下原來的省事。(這么講有點忽悠了)。

所以,在編程語言中,把實現(xiàn)上面那種拷貝的方式稱之為“淺拷貝”。顧名思義,沒有解決深層次問題。言外之意,還有能夠解決深層次問題的方法嘍。

的確是,在 Python 中,有一個“深拷貝”(deep copy)。不過,要用下一 import 來導(dǎo)入一個模塊。這個東西后面會講述,前面也遇到過了。

>>> import copy
>>> z = copy.deepcopy(x)
>>> z
{'lang': ['python', 'java'], 'name': 'qiwsir'}

copy.deepcopy()深拷貝了一個新的副本,看這個函數(shù)的名字就知道是深拷貝(deepcopy)。用上面用過的武器 id()來勘察一番:

>>> id(x["lang"])
3072243276L
>>> id(z["lang"])
3072245068L

果然是另外一個“窩”,不是引用了。如果按照這個結(jié)果,修改其中一個列表中的元素,應(yīng)該不影響另外一個了。

>>> x
{'lang': ['Python', 'java'], 'name': 'qiwsir'}
>>> x["lang"].remove("java")
>>> x
{'lang': ['Python'], 'name': 'qiwsir'}
>>> z
{'lang': ['Python', 'java'], 'name': 'qiwsir'}

果然如此。再試試,才過癮呀。

>>> x["lang"].append("c++")
>>> x
{'lang': ['Python', 'c++'], 'name': 'qiwsir'}

這就是所謂淺拷貝和深拷貝。

clear

在交互模式中,用 help 是一個很好的習(xí)慣

>>> help(dict.clear)

clear(...)
    D.clear() -> None.  Remove all items from D.

這是一個清空字典中所有元素的操作。

>>> a = {"name":"qiwsir"}
>>> a.clear()
>>> a
{}

這就是 clear 的含義,將字典清空,得到的是“空”字典。這個上節(jié)說的 del 有著很大的區(qū)別。del 是將字典刪除,內(nèi)存中就沒有它了,不是為“空”。

>>> del a
>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

果然刪除了。

另外,如果要清空一個字典,還能夠使用 a = {}這種方法,但這種方法本質(zhì)是將變量 a 轉(zhuǎn)向了{}這個對象,那么原來的呢?原來的成為了斷線的風(fēng)箏。這樣的東西在 Python 中稱之為垃圾,而且 Python 能夠自動的將這樣的垃圾回收。編程者就不用關(guān)心它了,反正 Python 會處理了。

get,setdefault

get 的含義是:

get(...)
    D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.

注意這個說明中,“if k in D”,就返回其值,否則...(等會再說)。

>>> d
{'lang': 'python'}
>>> d.get("lang")
'python'

dict.get()就是要得到字典中某個鍵的值,不過,它不是那么“嚴(yán)厲”罷了。因為類似獲得字典中鍵的值得方法,上節(jié)已經(jīng)有過,如 d['lang']就能得到對應(yīng)的值"Python",可是,如果要獲取的鍵不存在,如:

>>> print d.get("name")
None

>>> d["name"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'name'

這就是 dict.get()dict['key']的區(qū)別。

前面有一個半句話,如果鍵不在字典中,會返回 None,這是一種情況。還可以這樣:

>>> d = {"lang":"Python"}
>>> newd = d.get("name",'qiwsir')
>>> newd
'qiwsir'
>>> d
{'lang': 'Python'}

d.get("name",'qiwsir')的方式,如果不能得到鍵"name"的值,就返回后面指定的值"qiwsir"。這就是文檔中那句話:D[k] if k in D, else d.的含義。這樣做,并沒有影響原來的字典。

另外一個跟 get 在功能上有相似地方的 D.setdefault(k),其含義是:

setdefault(...)
    D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D

首先,它要執(zhí)行 D.get(k,d),就跟前面一樣了,然后,進(jìn)一步執(zhí)行另外一個操作,如果鍵k不在字典中,就在字典中增加這個鍵值對。當(dāng)然,如果有就沒有必要執(zhí)行這一步了。

>>> d
{'lang': 'Python'}
>>> d.setdefault("lang")
'Python'

在字典中,有"lang"這個鍵,那么就返回它的值。

>>> d.setdefault("name","qiwsir")
'qiwsir'
>>> d
{'lang': 'Python', 'name': 'qiwsir'}

沒有"name"這個鍵,于是返回 d.setdefault("name","qiwsir")指定的值"qiwsir",并且將鍵值對'name':"qiwsir"添加到原來的字典中。

如果這樣操作:

>>> d.setdefault("web")

什么也沒有返回嗎?不是,返回了,只不過沒有顯示出來,如果你用 print 就能看到了。因為這里返回的是一個 None.不妨查看一下那個字典。

>>> d
{'lang': 'Python', 'web': None, 'name': 'qiwsir'}

是不是鍵"web"的值成為了 None

items/iteritems, keys/iterkeys, values/itervalues

這個標(biāo)題中列出的是三組 dict 的函數(shù),并且這三組有相似的地方。在這里詳細(xì)講述第一組,其余兩組,我想憑借讀者的聰明智慧是不在話下的。

>>> help(dict.items)

items(...)
    D.items() -> list of D's (key, value) pairs, as 2-tuples

這種方法是慣用的伎倆了,只要在交互模式中鼓搗一下,就能得到幫助信息。從中就知道 D.items()能夠得到一個關(guān)于字典的列表,列表中的元素是由字典中的鍵和值組成的元組。例如:

>>> dd = {"name":"qiwsir", "lang":"python", "web":"www.itdiffer.com"}
>>> dd_kv = dd.items()
>>> dd_kv
[('lang', 'Python'), ('web', 'www.itdiffer.com'), ('name', 'qiwsir')]

顯然,是有返回值的。這個操作,在后面要講到的循環(huán)中,將有很大的作用。

items 類似的就是 iteritems,看這個詞的特點,是由 iter 和 items 拼接而成的,后部分 items 就不用說了,肯定是在告訴我們,得到的結(jié)果跟 D.items()的結(jié)果類似。是的,但是,還有一個 iter 是什么意思?在《列表(2)中,我提到了一個詞“iterable”,它的含義是“可迭代的”,這里的 iter 是指的名詞 iterator 的前部分,意思是“迭代器”。合起來,"iteritems"的含義就是:

iteritems(...)
    D.iteritems() -> an iterator over the (key, value) items of D

你看,學(xué)習(xí) Python 不是什么難事,只要充分使用幫助文檔就好了。這里告訴我們,得到的是一個“迭代器”(關(guān)于什么是迭代器,以及相關(guān)的內(nèi)容,后續(xù)會詳細(xì)講述),這個迭代器是關(guān)于“D.items()”的??磦€例子就明白了。

>>> dd
{'lang': 'Python', 'web': 'www.itdiffer.com', 'name': 'qiwsir'}
>>> dd_iter = dd.iteritems()
>>> type(dd_iter)
<type 'dictionary-itemiterator'>
>>> dd_iter
<dictionary-itemiterator object at 0xb72b9a2c>
>>> list(dd_iter)
[('lang', 'Python'), ('web', 'www.itdiffer.com'), ('name', 'qiwsir')]

得到的 dd_iter 的類型,是一個'dictionary-itemiterator'類型,不過這種迭代器類型的數(shù)據(jù)不能直接輸出,必須用 list()轉(zhuǎn)換一下,才能看到里面的真面目。

另外兩組,含義跟這個相似,只不過是得到 key 或者 value。下面僅列舉一下例子,具體內(nèi)容,讀者可以自行在交互模式中看文檔。

>>> dd
{'lang': 'Python', 'web': 'www.itdiffer.com', 'name': 'qiwsir'}
>>> dd.keys()
['lang', 'web', 'name']
>>> dd.values()
['Python', 'www.itdiffer.com', 'qiwsir']

這里先交代一句,如果要實現(xiàn)對鍵值對或者鍵或者值的循環(huán),用迭代器的效率會高一些。對這句話的理解,在后面會給大家進(jìn)行詳細(xì)分析。

pop, popitem

《列表(3)》中,有關(guān)于刪除列表中元素的函數(shù) popremove,這兩個的區(qū)別在于 list.remove(x)用來刪除指定的元素,而 list.pop([i])用于刪除指定索引的元素,如果不提供索引值,就默認(rèn)刪除最后一個。

在字典中,也有刪除鍵值對的函數(shù)。

pop(...)
    D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
    If key is not found, d is returned if given, otherwise KeyError is raised

D.pop(k[,d])是以字典的鍵為參數(shù),刪除指定鍵的鍵值對,當(dāng)然,如果輸入對應(yīng)的值也可以,那個是可選的。

>>> dd
{'lang': 'Python', 'web': 'www.itdiffer.com', 'name': 'qiwsir'}
>>> dd.pop("name")
'qiwsir'

要刪除指定鍵"name",返回了其值"qiwsir"。這樣,在原字典中,“'name':'qiwsir'”這個鍵值對就被刪除了。

>>> dd
{'lang': 'Python', 'web': 'www.itdiffer.com'}

值得注意的是,pop 函數(shù)中的參數(shù)是不能省略的,這跟列表中的那個 pop 有所不同。

>>> dd.pop()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pop expected at least 1 arguments, got 0

如果要刪除字典中沒有的鍵值對,也會報錯。

>>> dd.pop("name")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'name'

有意思的是 D.popitem()倒是跟 list.pop()有相似之處,不用寫參數(shù)(list.pop 是可以不寫參數(shù)),但是,D.popitem()不是刪除最后一個,前面已經(jīng)交代過了,dict 沒有順序,也就沒有最后和最先了,它是隨機(jī)刪除一個,并將所刪除的返回。

popitem(...)
    D.popitem() -> (k, v), remove and return some (key, value) pair as a 
    2-tuple; but raise KeyError if D is empty.

如果字典是空的,就要報錯了

>>> dd
{'lang': 'Python', 'web': 'www.itdiffer.com'}
>>> dd.popitem()
('lang', 'Python')
>>> dd
{'web': 'www.itdiffer.com'}

成功地刪除了一對,注意是隨機(jī)的,不是刪除前面顯示的最后一個。并且返回了刪除的內(nèi)容,返回的數(shù)據(jù)格式是 tuple

>>> dd.popitems()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'popitems'

錯了?!注意看提示信息,沒有那個...,哦,果然錯了。注意是 popitem,不要多了 s,前面的 D.items()中包含 s,是復(fù)數(shù)形式,說明它能夠返回多個結(jié)果(多個元組組成的列表),而在 D.popitem()中,一次只能隨機(jī)刪除一對鍵值對,并以一個元組的形式返回,所以,要單數(shù)形式,不能用復(fù)數(shù)形式了。

>>> dd.popitem()
('web', 'www.itdiffer.com')
>>> dd 
{}

都刪了,現(xiàn)在那個字典成空的了。如果再刪,會怎么樣?

>>> dd.popitem()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'popitem(): dictionary is empty'

報錯信息中明確告知,字典已經(jīng)是空的了,沒有再供刪的東西了。

update

update(),看名字就猜測到一二了,是不是更新字典內(nèi)容呢?的確是。

update(...)
    D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
    If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
    If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
    In either case, this is followed by: for k in F: D[k] = F[k]

不過,看樣子這個函數(shù)有點復(fù)雜。不要著急,通過實驗可以一點一點鼓搗明白的。

首先,這個函數(shù)沒有返回值,或者說返回值是 None,它的作用就是更新字典。其參數(shù)可以是字典或者某種可迭代的數(shù)據(jù)類型。

>>> d1 = {"lang":"python"}
>>> d2 = {"song":"I dreamed a dream"}
>>> d1.update(d2)
>>> d1
{'lang': 'Python', 'song': 'I dreamed a dream'}
>>> d2
{'song': 'I dreamed a dream'}

這樣就把字典 d2 更新入了 d1 那個字典,于是 d1 中就多了一些內(nèi)容,把 d2 的內(nèi)容包含進(jìn)來了。d2 當(dāng)然還存在,并沒有受到影響。

還可以用下面的方法更新:

>>> d2
{'song': 'I dreamed a dream'}
>>> d2.update([("name","qiwsir"), ("web","itdiffer.com")])
>>> d2
{'web': 'itdiffer.com', 'name': 'qiwsir', 'song': 'I dreamed a dream'}

列表的元組是鍵值對。

has_key

這個函數(shù)的功能是判斷字典中是否存在某個鍵

has_key(...)
    D.has_key(k) -> True if D has a key k, else False

跟前一節(jié)中遇到的 k in D 類似。

>>> d2
{'web': 'itdiffer.com', 'name': 'qiwsir', 'song': 'I dreamed a dream'}
>>> d2.has_key("web")
True
>>> "web" in d2
True

關(guān)于 dict 的函數(shù),似乎不少。但是,不用著急,也不用擔(dān)心記不住,因為根本不需要記憶。只要會用搜索即可。


總目錄   |   上節(jié):字典(1)   |   下節(jié):集合(1)

如果你認(rèn)為有必要打賞我,請通過支付寶:qiwsir@126.com,不勝感激。