python dict get 怎么实现的_关于python:dict.get()方法返回一个指针
假設(shè)我有這個(gè)代碼:
my_dict = {}
default_value = {'surname': '', 'age': 0}
# get info about john, or a default dict
item = my_dict.get('john', default_value)
# edit the data
item[surname] = 'smith'
item[age] = 68
my_dict['john'] = item
如果我們現(xiàn)在檢查默認(rèn)值,問題就變得很明顯了:
>>> default_value
{'age': 68, 'surname': 'smith'}
很明顯,my_dict.get()沒有返回默認(rèn)值,而是返回一個(gè)指針(?)對(duì)它。
通過將代碼更改為:
item = my_dict.get('john', {'surname': '', 'age': 0})
但這似乎不是一個(gè)很好的方法。有什么想法,意見嗎?
item = my_dict.get('john', default_value.copy())
您總是在python中傳遞一個(gè)引用。
對(duì)于不可變的對(duì)象,如str、int、tuple等,這并不重要。因?yàn)槟荒芨乃鼈?#xff0c;所以只能將名稱指向不同的對(duì)象,但對(duì)于易變的對(duì)象,如list、set和dict,它確實(shí)如此。你需要習(xí)慣這一點(diǎn)并時(shí)刻牢記在心。
編輯:ZachBloom和JonathanSternberg都指出了避免每次查找時(shí)調(diào)用copy的方法。您應(yīng)該使用defaultdict方法,類似于jonathan的第一種方法,或者:
def my_dict_get(key):
try:
item = my_dict[key]
except KeyError:
item = default_value.copy()
如果dict很大,當(dāng)密鑰幾乎總是存在于my_dict中時(shí),這將比if更快。您不必將它包裝在函數(shù)中,但您可能不希望每次訪問my_dict時(shí)都使用這四行。
看喬納森的回答,他用一個(gè)小的dict計(jì)時(shí)。在我測(cè)試的所有尺寸中,get方法表現(xiàn)不佳,但在大尺寸中,try方法表現(xiàn)更好。
這是Python的一個(gè)非常重要的原則——所有值都是通過引用傳遞的。這些引用的可變性是一個(gè)完全不同的問題(盡管它經(jīng)常以這種方式絆倒人們)。
我肯定我以前讀過,但當(dāng)你長(zhǎng)時(shí)間不使用一種語言時(shí),你往往會(huì)忘記一些事情。謝謝你說的清楚。
為什么你的答案與問題中提供的答案有任何不同?問題似乎更多的是找到一種優(yōu)雅的方法來返回新的dict實(shí)例,但只在需要時(shí)創(chuàng)建它。
問題是,他不必每次都輸入{'surname': '', 'age': 0},也不必每次都輸入get,而是通過擴(kuò)展說明如何在python中傳遞參數(shù),而不必每次都創(chuàng)建參數(shù)。不過,我已經(jīng)指出了其他提到這個(gè)問題的答案,并添加了一個(gè)備選方案。
@請(qǐng)看我的速度計(jì)時(shí)答案。使用try/except會(huì)比他想要的慢得多。
我做了更多的計(jì)時(shí),而且對(duì)于任何一個(gè)dict大小的get方法都不快,這讓我感到驚訝。但是,try方法比對(duì)大型dict的雙重查找要快,大約10000-1000000個(gè)條目的查找速度為10%。如果命中率很高,那么使用try是值得的。
-1:所有的值都在python中被賦值和傳遞。Python中的所有值都是引用(與Java中的非原語相同)。pass-by-reference"有一個(gè)非常具體的含義,即可以在調(diào)用范圍內(nèi)重新分配變量,而在python中則不是這樣。參見stackoverflow.com/questions/986006
是的,我在簡(jiǎn)化。我將編輯為說"你總是傳遞一個(gè)引用",而不是"通過引用",以免混淆那些可能從字面上理解它的人。
@agf:請(qǐng)注意,在調(diào)用my_dict.get('john', default_value.copy())時(shí),即使我的字典中有"john",default_value.copy()也會(huì)被執(zhí)行:即使沒有返回,也會(huì)創(chuàng)建一個(gè)默認(rèn)值的副本。這解釋了使用get方法時(shí)的部分性能問題。
@是的,我知道。你讀過這篇文章的其余部分嗎?或者其他答案?這就是整條線的意義所在。即使在其他構(gòu)造中使用dict.get(),它仍然有使用關(guān)鍵字不需要的開銷。
@阿格夫:你說得對(duì),我現(xiàn)在明白了,你和其他人確實(shí)提到過;對(duì)不起,我該閉嘴睡覺了……
@雷米哈哈,抱歉最后一句話的語氣,我貼出來的時(shí)候,實(shí)際上我正要去睡覺。
不要使用GET。你可以這樣做:
item = my_dict.get('john', default_value.copy())
但這要求即使字典條目存在,也要復(fù)制字典。相反,考慮檢查值是否存在。
item = my_dict['john'] if 'john' in my_dict else default_value.copy()
唯一的問題是它將對(duì)"john"執(zhí)行兩次查找,而不是一次。如果您愿意使用一個(gè)額外的行(并且沒有一個(gè)是您從字典中得到的可能值),您可以這樣做:
item = my_dict.get('john')
if item is None:
item = default_value.copy()
編輯:我想我會(huì)和timeit做一些速度比較。默認(rèn)值和我的口述是全局的。如果鑰匙在那里,如果有失手的話,我會(huì)為兩個(gè)人都做。
使用例外:
def my_dict_get():
try:
item = my_dict['key']
except KeyError:
item = default_value.copy()
# key present: 0.4179
# key absent: 3.3799
使用get并檢查它是否為none。
def my_dict_get():
item = my_dict.get('key')
if item is None:
item = default_value.copy()
# key present: 0.57189
# key absent: 0.96691
使用特殊的if/else語法檢查其存在性
def my_dict_get():
item = my_dict['key'] if 'key' in my_dict else default_value.copy()
# key present: 0.39721
# key absent: 0.43474
天真地抄寫字典。
def my_dict_get():
item = my_dict.get('key', default_value.copy())
# key present: 0.52303 (this may be lower than it should be as the dictionary I used was one element)
# key absent: 0.66045
在大多數(shù)情況下,除了使用異常的情況外,其他情況都非常相似。由于某種原因,特殊的if/else語法的時(shí)間似乎最短(不知道為什么)。
這是一個(gè)很好的觀點(diǎn),我會(huì)在我的答案中加上一個(gè)注釋。用'john' in my_dict代替my_dict.has_key('john'),用my_dict.get('john')代替my_dict.get('john', None),怎么樣?
我喜歡使用in,而不是has-key。我忘記了這一點(diǎn)。我不知道我的dict.get("john")默認(rèn)返回空值(我認(rèn)為這是一個(gè)indexerror)。
或者使用這個(gè):從集合導(dǎo)入defaultdict mydict=defaultdict(default_value.copy),然后在執(zhí)行mydict[此處沒有的鍵]時(shí),將調(diào)用傳遞給構(gòu)造函數(shù)的函數(shù)。
在python中,dict都是對(duì)象(因此它們總是作為引用傳遞)和可變對(duì)象(這意味著它們可以在不重新創(chuàng)建的情況下進(jìn)行更改)。
每次使用詞典時(shí),您都可以復(fù)制詞典:
my_dict.get('john', default_value.copy())
還可以使用defaultdict集合:
from collections import defaultdict
def factory():
return {'surname': '', 'age': 0}
my_dict = defaultdict(factory)
my_dict['john']
要認(rèn)識(shí)到的主要事情是,Python中的所有內(nèi)容都是通過引用傳遞的。C樣式語言中的變量名通常是內(nèi)存中對(duì)象形狀區(qū)域的簡(jiǎn)寫,將該變量賦值可復(fù)制另一個(gè)對(duì)象形狀區(qū)域…在Python中,變量只是字典(locals()中的鍵),而賦值操作只存儲(chǔ)新的引用。(從技術(shù)上講,一切都是一個(gè)指針,但這是一個(gè)實(shí)現(xiàn)細(xì)節(jié))。
這有許多含義,主要的含義是永遠(yuǎn)不會(huì)有一個(gè)對(duì)象的隱式副本,因?yàn)槟鷮⑺鼈鬟f給了一個(gè)函數(shù),分配了它,等等。獲得副本的唯一方法是顯式地這樣做。python stdlib提供了一個(gè)copy模塊,該模塊包含一些內(nèi)容,包括copy()和deepcopy()函數(shù),當(dāng)您想要顯式地復(fù)制某個(gè)內(nèi)容時(shí)。此外,有些類型公開了自己的.copy()功能,但這不是標(biāo)準(zhǔn),也不是一貫實(shí)現(xiàn)的。其他不可變的方法有時(shí)會(huì)提供一個(gè).replace()方法,這會(huì)產(chǎn)生一個(gè)變異的拷貝。
在代碼的情況下,傳遞原始實(shí)例顯然不起作用,并且提前(可能不需要時(shí))制作一個(gè)副本是浪費(fèi)的。所以最簡(jiǎn)單的解決方案可能是…
item = my_dict.get('john')
if item is None:
item = default_dict.copy()
在這種情況下,如果.get()支持傳入默認(rèn)值構(gòu)造函數(shù)函數(shù),這將非常有用,但這可能是在為邊界情況設(shè)計(jì)一個(gè)基類。
因?yàn)槊看握{(diào)用get時(shí),my_dict.get('john', default_value.copy())都會(huì)創(chuàng)建一個(gè)默認(rèn)dict的副本(即使當(dāng)出現(xiàn)并返回'john'時(shí)),所以使用此try/except選項(xiàng)更快也非常好:
try:
return my_dict['john']
except KeyError:
return {'surname': '', 'age': 0}
或者,您也可以使用defaultdict:
import collections
def default_factory():
return {'surname': '', 'age': 0}
my_dict = collections.defaultdict(default_factory)
總結(jié)
以上是生活随笔為你收集整理的python dict get 怎么实现的_关于python:dict.get()方法返回一个指针的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 三相电流滞环跟踪PWM控制
- 下一篇: 不平衡电网电压下虚拟同步发电机VSG控制