簡體   English   中英

什么是字典視圖對象?

[英]What are dictionary view objects?

在python 2.7中,我們獲得了可用的字典視圖方法

現在,我知道以下的利弊:

  • dict.items() (和valueskeys ):返回一個列表,這樣你就可以實際存儲結果,和
  • 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方法返回視圖 - 為什么?

主要原因是,對於許多用例而言,返回完全獨立的列表是不必要和浪費的。 它需要復制整個內容(可能或許多不是很多)。

如果您只想迭代密鑰,則無需創建新列表。 如果您確實需要它作為單獨的列表(作為副本),那么您可以從視圖中輕松創建該列表。

只是閱讀文檔,我得到了這樣的印象:

  1. 視圖是“偽設置”,因為它們不支持索引,因此您可以使用它們測試成員資格並對其進行迭代(因為鍵是可清除且唯一的,鍵和項視圖更多“像集一樣“因為它們不包含重復項”。
  2. 您可以存儲它們並多次使用它們,例如列表版本。
  3. 因為它們反映了基礎字典,所以字典中的任何更改都將改變視圖,並且幾乎肯定會改變迭代的順序 因此與列表版本不同,它們不是“穩定”的。
  4. 因為它們反映了基礎字典,所以它們幾乎肯定是小代理對象; 復制鍵/值/項將要求他們以某種方式觀看原始字典並在發生更改時多次復制,這將是一個荒謬的實現。 所以我期望很少的內存開銷,但訪問速度比直接到字典要慢一些。

所以我想關鍵的用例是如果你保持一個字典並反復迭代它的鍵/項/值,並在兩者之間進行修改。 您可以只使用視圖, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM