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