[英]In python, how does the following AutoVivification class work?
在尋找使用嵌套字典的方法時,我發現nosklo發布了以下代碼,我想解釋一下。
class AutoVivification(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
測試:
a = AutoVivification()
a[1][2][3] = 4
a[1][3][3] = 5
a[1][2]['test'] = 6
print a
輸出:
{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}}
我是一個非常新手的程序員。 我在自己的時間里學到了大部分我所知道的知識,我在高中時只接受過Turbo Pascal的正式訓練。 我理解並能夠以簡單的方式使用類,例如使用__init__
,類方法,並使用foo.man = 'choo'
在類的實例中存儲數據。
我不知道方括號系列是如何正確地通過類來定向的(我假設它們以某種方式調用__getitem__
)並且不理解它們如何被如此簡潔地處理,而不必單獨調用該方法三次。
我的印象是,類聲明中的(dict)
將由__init__
處理。
我曾經try: except:
之前,盡管如此,以非常簡單的方式。 它看起來像try
,當它運行時,正在調用一系列函數__getitem__
。 我知道如果當前級別的字典存在,則try將通過並轉到下一個字典。 我收集的except
,當有一個KeyError
時運行,但我還沒有看到過像以前那樣的self
使用。 當我認為self
是一個class AutoVivification
一個實例時, Self
被視為字典......它是兩個嗎? 我從來沒有像這樣連續兩次分配foo = man = choo
但懷疑value
指向self[item]
而self[item]
指向type(self)
的結果。 但是type(self)
會返回類似這樣的內容: <class '__main__.AutoVivification'>
不是嗎? 我不知道最后有什么額外的圓括號。 因為我不知道如何調用函數,我不明白返回value
位置。
抱歉有這些問題! 有這么多,我不明白,我不知道在哪里查閱,只需閱讀文檔幾個小時,我保留很少。 這段代碼看起來像是為了我的目的但我想在使用之前理解它。
如果你想知道我在我的程序中嘗試使用嵌套字典做什么:我試圖以天文數字的形式保存地圖數據。 雖然我無法創建嵌套4次的10 ^ 6項的字典/列表(也就是10 ^ 24項!),但空間大部分都是空的,所以我可以完全保留空值,只有在那里有東西時才分配。 困擾我的是處理字典的有效方式。
逐行:
class AutoVivification(dict):
我們創建了一個dict
的子類,所以AutoVivification
是一種dict
,有一些局部的變化。
def __getitem__(self, item):
該__getitem()__
鈎被稱為每當有人試圖通過對實例訪問項目[...]
索引查找。 因此,每當有人對object[somekey]
, type(object).__getitem__(object, somekey)
被調用。
我們暫時跳過try
,下一行是:
return dict.__getitem__(self, item)
這將調用未綁定的方法__getitem__()
,並將自己的實例與密鑰一起傳遞給它。 換句話說,我們稱之為父類dict
定義的原始 __getitem__
。
現在,我們都知道如果字典中沒有item
密鑰會發生什么,會引發KeyError
。 這是try:
, except KeyError
組合except KeyError
:
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
所以,如果目前的情況下(這是子類型的dict
)沒有給定的鍵,它會捕捉KeyError
例外原來dict.__getitem__()
方法拋出,而是我們創造了新的價值,商店在self[item]
並返回該值。
現在,請記住self
是dict
的(子類),所以它是一個字典。 因此,它可以分配新的值(它將使用__setitem__
鈎子 ,並且在這種情況下,它會創建一個與self
相同類型的新實例)。 這是另一個dict
子類。
那么當我們稱a[1][2][3] = 4
什么呢? Python經歷了這一步:
a[1]
導致type(a).__getitem__(a, 1)
。 自定義__getitem__
的方法AutoVivification
捕獲KeyError
,創建的新實例AutoVivification
,賣場,根據鍵1
和返回。
a[1]
返回一個空的AutoVivification
實例。 在該對象上調用下一個項[2]
,我們重復步驟1中發生的事情; 有一個KeyError
,的新實例AutoVivification
創建,下保存2
鍵,新的實例返回給調用者。
a[1][2]
返回一個空的AutoVivification
實例。 在該對象上調用下一個訪問項[3]
,我們重復步驟1(和步驟2)中發生的事情。 有一個KeyError
,的新實例AutoVivification
創建,在存儲的3
鍵,而新的實例返回給調用者。
a[1][2][3]
返回一個空的AutoVivification
實例。 現在我們在該實例中存儲一個新值, 4
。
一旦你轉到下一行代碼, a[1][3][3] = 5
,頂級AutoVivification
實例已經有一個1
鍵, return dict.__getitem__(self, item)
行將返回相應的值,恰好是上面第一步中創建的AutoVivification
實例。
從那里, [3]
項訪問調用將再次創建一個新的AutoVivification
實例(因為a[1]
處的對象只有一個2
鍵),我們再次執行所有相同的步驟。
查看object.__getitem__
文檔,開始。
class AutoVivification(dict)
聲明使AutoVivification
成為dict
的子類,因此它的行為與dict
相同,除非它明確地覆蓋某些行為 - 正如此類在覆蓋__getitem__
時所做的那樣。
對dict.__getitem__(self, item)
的調用通常會被寫為:
super(AutoVivification, self).__getitem__(item)
(至少在Python 2.x中; Python 3有更好的語法。)無論哪種方式,它的作用是嘗試讓默認的dict
行為運行,但是在不起作用的情況下實現回退。
type(self)()
首先查找與self
實例對應的類對象,然后調用類對象 - 在這種情況下與編寫AutoVivification()
相同,這應該看起來更熟悉。
希望能為你清理它!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.