[英]What are dictionary view objects?
在python 2.7中,我們獲得了可用的字典視圖方法 。
現在,我知道以下的利弊:
dict.items()
(和values
, keys
):返回一個列表,這樣你就可以實際存儲結果,和 dict.iteritems()
(等):返回一個生成器,因此你可以迭代生成逐個生成的每個值。 什么是dict.viewitems()
(等)? 他們有什么好處? 它是如何工作的? 什么是觀點?
我讀到視圖總是反映字典中的變化。 但是從性能和內存的角度來看它是如何表現的呢? 有什么利弊?
字典視圖基本上就是他們的名字所說的: 視圖就像一個關於字典的鍵和值(或項)的窗口 。 以下是Python 3 官方文檔的摘錄:
>>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500}
>>> keys = dishes.keys()
>>> values = dishes.values()
>>> # view objects are dynamic and reflect dict changes
>>> del dishes['eggs']
>>> keys # No eggs anymore!
dict_keys(['sausage', 'bacon', 'spam'])
>>> values # No eggs value (2) anymore!
dict_values([1, 1, 500])
(Python 2等效使用dishes.viewkeys()
和dishes.viewvalues()
。)
此示例顯示了視圖的動態特性 :鍵視圖不是給定時間點的鍵的副本,而是一個向您顯示鍵的簡單窗口; 如果它們被改變了,那么你在窗口看到的東西也會發生變化。 在某些情況下,此功能非常有用(例如,可以使用程序的多個部分中的鍵的視圖,而不是每次需要時重新計算當前的鍵列表) - 注意如果修改了字典鍵迭代視圖時,迭代器的行為方式沒有明確定義,這可能導致錯誤 。
一個優點是,例如, 查看密鑰僅使用少量固定數量的內存,並且需要少量且固定數量的處理器時間 ,因為沒有創建密鑰列表(另一方面,Python 2,通常不必要地創建一個新的列表,如Rajendran T引用的那樣,它占用的內存和時間與列表的長度成比例)。 要繼續窗口類比,如果你想看到牆后面的風景,你只需在其中打開一個開口(你建立一個窗口); 將密鑰復制到列表中將相應於在牆上繪制景觀的副本 - 復制需要時間,空間,並且不會自行更新。
總而言之,視圖只是...字典上的視圖(窗口),即使在更改后也會顯示字典的內容。 它們提供的功能與列表的功能不同:鍵列表包含給定時間點的字典鍵副本 ,而視圖是動態的,獲取速度更快,因為它不需要復制任何數據(鍵或值)以便創建。
正如您所提到的, dict.items()
返回字典的(鍵,值)對列表的副本,這是浪費的, dict.iteritems()
返回字典(鍵,值)對上的迭代器。
現在采用以下示例來查看dict的interator和dict的視圖之間的區別
>>> d = {"x":5, "y":3}
>>> iter = d.iteritems()
>>> del d["x"]
>>> for i in iter: print i
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
而視圖只是向您顯示字典中的內容。 它不關心它是否改變:
>>> d = {"x":5, "y":3}
>>> v = d.viewitems()
>>> v
dict_items([('y', 3), ('x', 5)])
>>> del d["x"]
>>> v
dict_items([('y', 3)])
視圖只是字典現在的樣子。 刪除條目后, .items()
會過時,而.iteritems()
會拋出錯誤。
視圖方法返回一個列表(不是列表的副本,與.keys()
.items()
和.values()
),因此它更輕量級,但反映了字典的當前內容。
從Python 3.0 - dict方法返回視圖 - 為什么?
主要原因是,對於許多用例而言,返回完全獨立的列表是不必要和浪費的。 它需要復制整個內容(可能或許多不是很多)。
如果您只想迭代密鑰,則無需創建新列表。 如果您確實需要它作為單獨的列表(作為副本),那么您可以從視圖中輕松創建該列表。
只是閱讀文檔,我得到了這樣的印象:
所以我想關鍵的用例是如果你保持一個字典並反復迭代它的鍵/項/值,並在兩者之間進行修改。 您可以只使用視圖, for k, v in mydict.iteritems():
轉換for k, v in myview:
轉換for k, v in myview:
. 但如果你只是在字典上迭代一次,我認為iter-版本仍然更可取。
通過視圖,您可以訪問底層數據結構,而無需復制它。 除了是動態的,而不是創造一個名單,他們最有用的用途之一是in
測試。 假設您要檢查某個值是否在dict中(無論是鍵還是值)。
選項一是使用dict.keys()
創建一個鍵列表,這可以工作,但顯然會消耗更多的內存。 如果dict非常大? 那將是浪費。
使用views
您可以迭代實際的數據結構,而無需中間列表。
我們來看一些例子。 我有一個帶有1000個隨機字符串和數字鍵的字典, k
是我想要查找的鍵
large_d = { .. 'NBBDC': '0RMLH', 'E01AS': 'UAZIQ', 'G0SSL': '6117Y', 'LYBZ7': 'VC8JQ' .. }
>>> len(large_d)
1000
# this is one option; It creates the keys() list every time, it's here just for the example
timeit.timeit('k in large_d.keys()', setup='from __main__ import large_d, k', number=1000000)
13.748743600954867
# now let's create the list first; only then check for containment
>>> list_keys = large_d.keys()
>>> timeit.timeit('k in list_keys', setup='from __main__ import large_d, k, list_keys', number=1000000)
8.874809793833492
# this saves us ~5 seconds. Great!
# let's try the views now
>>> timeit.timeit('k in large_d.viewkeys()', setup='from __main__ import large_d, k', number=1000000)
0.08828549011070663
# How about saving another 8.5 seconds?
正如您所看到的,迭代view
對象可以極大地提升性能,同時減少內存開銷。 當您需要執行Set
like operations時,您應該使用它們。
注意 :我正在運行Python 2.7
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.