Sözlük görüntüleme nesneleri nedir?


159

Python 2.7'de sözlük görüntüleme yöntemlerini kullanıma sunduk .

Şimdi, aşağıdakilerin yanlısı ve eksilerini biliyorum:

  • dict.items()(ve values, keys): bir liste döndürür, böylece sonucu gerçekten depolayabilirsiniz ve
  • dict.iteritems() (ve benzeri): bir jeneratör döndürür, böylece üretilen her bir değeri tek tek yineleyebilirsiniz.

Ne için dict.viewitems()(ve benzerleri)? Avantajları nelerdir? O nasıl çalışır? Ne de olsa görüş nedir?

Görünümün daima sözlükteki değişiklikleri yansıttığını okudum. Peki bu mükemmel ve hafıza açısından nasıl davranıyor? Artıları ve eksileri nelerdir?

Yanıtlar:


157

Sözlük görünümleri aslında adlarının söylediği şeydir: görünümler bir sözlüğün anahtarları ve değerleri (veya öğeleri) üzerindeki bir pencere gibidir . İşte Python 3 için resmi belgelerden bir alıntı :

>>> 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 eşdeğeri dishes.viewkeys()ve kullanır dishes.viewvalues().)

Bu örnek gösterir görüş dinamik karakteri : tuşları görüntülemek olduğu değil zaman içinde belirli bir noktada tuşların bir kopyası değil, basit bir pencere gösterir Anahtarlar; değiştirildiyse, pencereden gördükleriniz de değişir. Bu özellik bazı durumlarda yararlı olabilir (örneğin, her gerekli olduklarında geçerli anahtar listesini yeniden hesaplamak yerine bir programın birden çok bölümündeki tuşlar üzerinde bir görünümle çalışılabilir); görünüm üzerinde yineleme yaparken yineleyicinin nasıl davranması gerektiği iyi tanımlanmamıştır ve bu da hatalara yol açabilir .

Bir avantajı , diyelim ki, tuşlara bakmak sadece küçük ve sabit bir bellek kullanır ve bir anahtar listesi oluşturulmadığı için küçük ve sabit bir işlemci süresi gerektirir (Öte yandan, Python 2, genellikle gereksiz yere Rajendran T tarafından alıntılandığı gibi, listenin uzunluğuyla orantılı bir miktarda bellek ve zaman alan yeni bir liste oluşturur). Pencere benzetmesine devam etmek için, bir duvarın arkasında bir manzara görmek istiyorsanız, sadece bir açıklık yaparsınız (bir pencere inşa edersiniz); anahtarları bir listeye kopyalamak, bunun yerine duvardaki manzaranın bir kopyasını boyamaya karşılık gelir - kopya zaman, yer kaplar ve kendini güncellemez.

Özetlemek gerekirse, görünümler basitçe… sözlüğünüzde değiştikten sonra bile içeriğini gösteren görünümlerdir (pencereler). Listelerinkinden farklı özellikler sunarlar: bir anahtar listesi, belirli bir zamanda sözlük anahtarlarının bir kopyasını içerirken, bir görünüm dinamiktir ve herhangi bir veri kopyalamak zorunda olmadığından elde edilmesi çok daha hızlıdır ( anahtarlar veya değerler) oluşturabilirsiniz.


6
+1. Tamam, bunun dahili anahtar listesine doğrudan erişmekten farkı nedir? Bu daha hızlı, daha yavaş mı? Daha fazla bellek verimli mi? Kısıtlı ? Okuyup düzenleyebiliyorsanız, bu listeye referans vermekle tamamen aynıdır.
e-satis

3
Teşekkürler. Şey görünümleri olduğunu vardır senin "tuşları iç listesi" erişim (bu "tuşlarının listesi" olsa da, bir Python liste değildir, ama kesin bir görünüm olduğunu not). Görünümler Python 2'nin anahtar listelerinden (veya değerlerinden veya öğelerinden) daha bellek verimlidir, çünkü hiçbir şey kopyalamazlar; gerçekten de "anahtarlar listesine bir referans" gibidirler (listenin değiştirilebilir nesneler olduğu için Python'da "bir listeye yapılan bir referansın" aslında bir liste olarak adlandırıldığını da unutmayın). Ayrıca görünümleri doğrudan düzenleyemeyeceğinizi de unutmayın: bunun yerine sözlüğü hala düzenlersiniz ve görünümler değişikliklerinizi hemen yansıtır.
Eric O Lebigot

3
Tamam, henüz uygulama konusunda net değilim, ama şu ana kadarki en iyi cevap bu.
e-satis

2
Teşekkürler. Aslında bu cevap çoğunlukla görüşlerin anlambilimi ile ilgilidir. CPython uygulama hakkında bilgi yok, ama bir görünüm temelde doğru yapı (lar) (anahtarlar ve / veya değerler) bir işaretçi olduğunu ve yapıları sözlük nesnesinin bir parçası olduğunu tahmin ediyorum.
Eric O Lebigot

5
Bu yazıdaki örnek kodun python3'ten olduğunu ve python2.7'de aldığım şey olmadığını belirtmeye değer olduğunu düşünüyorum.
Snth

21

Bahsettiğiniz gibi dict.items(), sözlüğün (anahtar, değer) çiftleri listesinin bir kopyasını döndürür, bu da savurgan ve dict.iteritems()sözlüğün (anahtar, değer) çiftleri üzerinde bir yineleyici döndürür.

Şimdi bir dict interator ve dict görünümü arasındaki farkı görmek için aşağıdaki örneği alın

>>> 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

Oysa bir görüş size dikte ne olduğunu gösterir. Değişip değişmediği umurumda değil:

>>> d = {"x":5, "y":3}
>>> v = d.viewitems()
>>> v
dict_items([('y', 3), ('x', 5)])
>>> del d["x"]
>>> v
dict_items([('y', 3)])

Bir görünüm, sözlüğün şimdi nasıl göründüğü ile ilgilidir. Silindikten sonra bir giriş .items()güncelliğini .iteritems()yitirir ve bir hata atar.


Harika bir örnek, teşekkürler. Yine de, v = d.items () değil v - d.viewitems ()
rix olmalıdır

1
Soru Python 2.7 ile ilgili, bu yüzden viewitems()gerçekten doğru ( items()Python 3'te doğru bir görünüm verir ).
Eric O Lebigot

Ancak, görünüm , sözlük değiştirilirken sözlük üzerinden yinelenmek için kullanılamaz.
Ioannis Filippidis

18

Sadece dokümanları okurken bu izlenimi edinebilirim:

  1. Görünümler "sözde set benzeri", endekslemeyi desteklemedikleri için onlarla yapabileceğiniz şey üyelik testi ve yineleme yapmaktır (anahtarlar yıkanabilir ve benzersiz olduğundan, anahtarlar ve öğe görünümleri daha fazladır " set benzeri gibi "olarak adlandırılır).
  2. Bunları depolayabilir ve liste sürümleri gibi birden çok kez kullanabilirsiniz.
  3. Temel sözlüğü yansıttıkları için, sözlükteki herhangi bir değişiklik görünümü değiştirecek ve yineleme sırasını neredeyse kesinlikle değiştirecektir . Yani liste versiyonlarından farklı olarak, "kararlı" değiller.
  4. Temel sözlüğü yansıttıkları için neredeyse kesinlikle küçük proxy nesnelerdir; anahtarların / değerlerin / öğelerin kopyalanması, orijinal sözlüğü bir şekilde izlemelerini ve değişiklikler meydana geldiğinde birden çok kez kopyalamasını gerektirir; bu, saçma bir uygulama olacaktır. Bu yüzden çok az bellek yükü beklerdim, ancak erişim doğrudan sözlüğe göre biraz daha yavaş olur.

Bu yüzden anahtar usecase, bir sözlük tutuyorsanız ve aralarında değişiklikler yaparak anahtarları / öğeleri / değerleri üzerinde tekrar tekrar yineliyorsanız. Sadece dönüm, bunun yerine bir görünüm kullanabilirsiniz for k, v in mydict.iteritems():içine for k, v in myview:. Ancak sadece bir kez sözlüğü tekrarlıyorsanız, sürümlerin hala tercih edilebilir olduğunu düşünüyorum.


2
Elimizdeki birkaç bilgiden pro ve eksilerini analiz etmek için +1.
e-satis

Bir görünüm üzerinde yineleyici oluşturursam, sözlük her değiştiğinde yine de geçersiz kılınır. Bu, sözlüğün kendisinde bir yineleyici ile aynı sorun (örn. iteritems()). Peki bu görüşlerin anlamı nedir? Onlara sahip olduğum için ne zaman mutluyum?
Alfe

@Alfe Haklısınız, bu sözlük yinelemesinde bir sorun ve görünümler hiç yardımcı olmuyor. Bir sözlüğün değerlerini bir işleve iletmeniz gerektiğini varsayalım. Kullanabilirsiniz .values(), ancak bu bir liste olarak bir bütün kopya yapmayı içerir, bu da pahalı olabilir. Var .itervalues()ama bunları bir kereden fazla tüketemezsiniz, bu yüzden her işlevle çalışmaz. Görünümler pahalı bir kopya gerektirmez, ancak yine de tek başına bir değer olarak yineleyiciden daha kullanışlıdır. Ancak yine de aynı anda yineleme ve değiştirme konusunda yardımcı olmaları amaçlanmamıştır (orada gerçekten bir kopya istiyorsunuz).
Ben

17

Görünüm yöntemleri listesini (bir oranla listenin kopyası, dönmek .keys(), .items()ve .values()daha hafiftir, fakat sözlüğe geçerli içeriğini yansıtır böylece,).

Gönderen Python 3.0 - dict yöntemleri görüşlerini dönmek - neden?

Bunun ana nedeni, tamamen ayrılmış bir listeyi döndüren birçok kullanım durumunda gereksiz ve israftır. Tüm içeriğin kopyalanmasını gerektirir (bu çok fazla olabilir veya çok fazla olmayabilir).

Sadece tuşlar üzerinde yineleme yapmak istiyorsanız, yeni bir liste oluşturmak gerekli değildir. Ve gerçekten de ayrı bir liste olarak (bir kopya olarak) ihtiyacınız varsa, o listeyi görünümden kolayca oluşturabilirsiniz.


6
Görünüm yöntemleri, liste arabirimine uymayan görünüm nesnelerini döndürür.
Matthew Trevor

5

Görünümler, altta yatan veri yapısına kopyalamadan erişmenizi sağlar. Liste oluşturmanın aksine dinamik olmanın yanı sıra, en kullanışlı kullanımlarından biri de intesttir. Bir değerin sözlükte olup olmadığını kontrol etmek istediğinizi varsayalım (anahtar veya değer olabilir).

Birinci seçenek, tuşların bir listesini oluşturmaktır dict.keys(), bu çalışır, ancak daha fazla bellek tüketir. Karar çok büyükse? Bu savurgan olurdu.

İle viewsara liste olmadan gerçek veri yapısını tekrarlayabilirsiniz.

Örnekler kullanalım. Rastgele dizelerin ve rakamların 1000 tuşuyla bir kararım var ve karamak istediğim anahtar

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?

Gördüğünüz gibi, yinelenen viewnesne performansta büyük bir artış sağlar ve aynı zamanda bellek ek yükünü azaltır. SetBenzer işlemleri gerçekleştirmeniz gerektiğinde bunları kullanmalısınız .

Not : Python 2.7 ile çalışıyorum


Python> = 3'te, .keys()varsayılan olarak bir görünüm döndürdüğüne inanıyorum . Tho çift kontrol etmek isteyebilirsiniz
Yolo Voe

1
Haklısın. Python 3+, listeler yerine görüntüleme nesnelerini yoğun bir şekilde kullanır, çok daha fazla bellek verimlidir
Chen A.

1
Bu zamanlama sonuçlar çok söylüyorum ama olsun kontrol ediyoruz ksözlüğün anahtarlarından biridir large_dyapılabilir anlamına gelir k in large_dbaşka bir deyişle, (a görünümünü kullanarak esasen kadar hızlı muhtemelen Python içinde, k in large_d.keys()Pythonic değildir ve avoided- olmalı olduğu gibi k in large_d.viewkeys()).
Eric O Lebigot

Sağlam ve faydalı bir örnek verdiğiniz için teşekkür ederiz. k in large_daslında bundan çok daha hızlıdır k in large_d.viewkeys(), bundan kaçınılması gerekir, ancak bu mantıklıdır k in large_d.viewvalues().
naught101
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.