Python'da sözlüğü kopyalamanın hızlı yolu


92

Sözlüklerle çokça çalışan bir Python programım var. Sözlüklerin kopyalarını binlerce kez çıkarmam gerekiyor. Hem anahtarların hem de ilgili içeriğin bir kopyasına ihtiyacım var. Kopya düzenlenecek ve orijinal ile bağlantılı olmamalıdır (örneğin, kopyadaki değişiklikler orijinali etkilememelidir.)

Anahtarlar Dizelerdir, Değerler Tamsayılardır (0/1).

Şu anda basit bir yol kullanıyorum:

newDict = oldDict.copy()

Kodumun profilini oluşturmak, kopyalama işleminin çoğu zaman sürdüğünü gösterir.

dict.copy()Yöntemin daha hızlı alternatifleri var mı? En hızlı ne olurdu?


1
Değer 0 veya 1 olabiliyorsa, a'dan booldaha iyi bir seçim olur intmu?
Samir Talwar

5
Ve bunların binlerce kopyasına ihtiyacınız varsa, bit maskeler daha da iyi çalışır mı?
Wooble

@Samir zaten booladlandırılmış Python'da değil int.
Noel Baba

Yine de, bir bit maskesinin sizin için daha verimli olabileceğine katılıyorum (bu "dikteyi" nasıl kullandığınıza bağlı olarak, gerçekten).
Noel Baba

1
Açıklığa kavuşturmak gerekirse, booltür aslında türün bir alt sınıfıdır (alt tür?) int.
Noel Baba

Yanıtlar:


64

Python işlemleri için C kaynağına baktığınızda, dictoldukça saf (ama verimli) bir kopya yaptıklarını görebilirsiniz. Esasen bir çağrıya dönüşür PyDict_Merge:

PyDict_Merge(PyObject *a, PyObject *b, int override)

Bu, aynı nesne olup olmadıkları ve içinde nesneler olup olmadığı gibi şeyleri hızlıca kontrol eder. Bundan sonra, hedef dikte için cömert bir defalık yeniden boyutlandırma / tahsis yapar ve ardından öğeleri tek tek kopyalar. Yerleşik olandan çok daha hızlı olduğunu görmüyorum copy().


1
Görünüşe göre dikt kullanımından kaçınmak için kodu yeniden yazmam veya aynı işi yapabilen daha hızlı bir veri yapısı kullanmam daha iyi. Cevabınız için çok teşekkür ederim!
Joern

56

Görünüşe göre dict.copy, dediğiniz gibi daha hızlıdır.

[utdmr@utdmr-arch ~]$ python -m timeit -s "d={1:1, 2:2, 3:3}" "new = d.copy()"
1000000 loops, best of 3: 0.238 usec per loop
[utdmr@utdmr-arch ~]$ python -m timeit -s "d={1:1, 2:2, 3:3}" "new = dict(d)"
1000000 loops, best of 3: 0.621 usec per loop
[utdmr@utdmr-arch ~]$ python -m timeit -s "from copy import copy; d={1:1, 2:2, 3:3}" "new = copy(d)"
1000000 loops, best of 3: 1.58 usec per loop

Karşılaştırma için teşekkürler! Çoğu yerde dikt kopyalamanın kullanılmasını önlemek için kodu yeniden yazmaya çalışacaktır. Tekrar teşekkürler!
Joern

4
Yolu her zaman sahip olduğu ithalat yapma maliyetini saymadan son karşılaştırma yapmak timeitbireyin -sargüman: python -m timeit -s "from copy import copy" "new = copy({1:1, 2:2, 3:3})". Hazır oradayken, dikte oluşturmayı da çıkarın (tüm örnekler için)
Thomas Wouters

Belirli bir çekimde bazı dalgalanmalar olabileceğinden, süreçleri birçok kez tekrarlamak daha iyidir.
xiaohan2012

2
Timeit bunu yapar; söylediği gibi 1000000 kez döngü yapar ve ortalamasını alır.
utdemir

Çakışan zamanlamalarım var. a = {b: b için aralık (10000)} In [5]:% timeit kopya (a) 10000 döngü, en iyi döngü başına 3: 186 µs In [6]:% timeit deepcopy (a) 100 döngü, Döngü başına 3: 14.1 ms'nin en iyisi In [7]:% timeit a.copy () 1000 döngü, döngü başına en iyisi 3: 180 µs
Davoud Taghawi-Nejad,

12

Copy () 'yi nasıl ve hangi bağlamda kullandığınızı görebilmem için bir kod örneği sağlayabilir misiniz?

Kullanabilirsin

new = dict(old)

Ama daha hızlı olacağını sanmıyorum.


5

Bunun eski bir iş parçacığı olduğunun farkındayım, ancak bu, arama motorlarında "dikte python kopya" için yüksek bir sonuç ve "dikte kopya performansı" için en iyi sonuç ve bunun alakalı olduğuna inanıyorum.

Python newDict = oldDict.copy()3.7'den, öncekinden 5,5 kata kadar daha hızlıdır. Özellikle şu newDict = dict(oldDict)anda bu performans artışına sahip görünmüyor.

Burada biraz daha bilgi var .


3

Spekülasyona bıraktığınız şeylere bağlı olarak, orijinal sözlüğü kapatıp bir tür yazma üzerine kopyalama .

Bu durumda, "kopya", eğer zaten anahtarı içermiyorsa - ama değişiklikleri kendi içinde dolduruyorsa, "ana" sözlükte bir şeyler arayan bir sözlüktür.

Bu, orijinali değiştirmeyeceğinizi ve fazladan aramaların daha pahalıya mal olmayacağını varsayar.


2

Ölçüler sözlük boyutuna bağlıdır. 10000 giriş için copy (d) ve d.copy () hemen hemen aynıdır.

a = {b: b for b in range(10000)} 
In [5]: %timeit copy(a)
10000 loops, best of 3: 186 µs per loop
In [6]: %timeit deepcopy(a)
100 loops, best of 3: 14.1 ms per loop
In [7]: %timeit a.copy()
1000 loops, best of 3: 180 µs per loop
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.