Python setleri ekleme siparişini neden korumuyor?


12

Son zamanlarda Python 3.7+ 'de ekleme siparişi korumak için garantiler garanti edilirken, setler olmadığını keşfetmek için şaşırdım:

>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> d
{'a': 1, 'b': 2, 'c': 3}
>>> d['d'] = 4
>>> d
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
>>> s = {'a', 'b', 'c'}
>>> s
{'b', 'a', 'c'}
>>> s.add('d')
>>> s
{'d', 'b', 'a', 'c'}

Bu farkın mantığı nedir? Python ekibinin, diksiyon uygulamasını değiştirmesine neden olan aynı verimlilik iyileştirmeleri setler için de geçerli değil mi?

Sipariş edilen set uygulamalarına ya da diktleri setler için stand-in olarak kullanma yollarına bakmıyorum. Sadece Python ekibinin neden dicts için yaptıkları aynı zamanda siparişleri korumak için yerleşik setler yapmadığını merak ediyorum.



1
Hayır, Python'un yerleşik bir sipariş seti olmadığını anlıyorum.
Bart Robinson

4
Kullanım kalıpları farklı olduğundan farklı kullanım durumları için optimize edilmiştir. Kümelerin sadece CPython'da null değerlere sahip dikteler olduğu yaygın bir yanlış anlamadır, bu tamamen yanlıştır: uygulamalar farklıdır. Sorunuz kapanmazsa, ayrıntılı bir cevap gönderebilirim.
wim

1
"Kullanım kalıpları farklı olduğundan farklı kullanım durumları için optimize edilmiştir." Soruna iyi bir cevap bunun üzerinde durulabilir diye düşünüyorum. Soru, iki farklı yaklaşımı karşılık gelen kullanım durumları için neyin en uygun hale getirdiği ile ilgilidir.
Karl Knechtel

PyPy'nin her ikisi için dictve set2.7'den beri aynı sıralamayı kullandığını unutmayın .
MisterMiyagi

Yanıtlar:


10

Setler ve dikmeler farklı kullanım durumları için optimize edilmiştir. Bir kümenin birincil kullanımı, sipariş agnostik olan hızlı üyelik testidir. Dikte için, arama maliyeti en kritik işlemdir ve anahtarın bulunması daha olasıdır. Kümelerde, bir öğenin varlığı veya yokluğu önceden bilinmemektedir ve bu nedenle küme uygulamasının hem bulunan hem de bulunmayan durum için optimize etmesi gerekir. Ayrıca, birleşim ve kavşak gibi yaygın küme işlemleri için yapılan bazı optimizasyonlar, performansı düşürmeden küme sırasını korumayı zorlaştırır.

Her iki veri yapısı da karma tabanlı olsa da, kümelerin sadece null değerlere sahip diktler olarak uygulanması yaygın bir yanlış anlamadır. HattaCPython 3.6'daki kompakt dict uygulamasından önce , set ve dict uygulamaları çok az kod kullanımıyla zaten önemli ölçüde farklıydı. Örneğin, dikteler rastgele problama kullanır, ancak kümeler önbellek yerini iyileştirmek için doğrusal problama ve açık adresleme kombinasyonunu kullanır. İlk doğrusal prob ( CPython'da varsayılan 9 adım ), bir dizi bitişik anahtar / karma çiftini kontrol edecek ve karma çarpışma işleme maliyetini azaltarak performansı artıracaktır - ardışık bellek erişimi dağınık problardan daha ucuzdur.

  • dictobject.c- usta , v3.5.9
  • setobject.c - usta , v3.5.9
  • issue18771 - Python 3.4'te ayarlanan nesneler için karma çarpışmaların maliyetini azaltmak için değişiklik kümesi.

Olurdu mümkün kompakt dict benzer olması CPython seti uygulamasını değiştirme teoride ama pratikte dezavantajları vardır ve önemli çekirdek geliştiricileri böyle bir değişiklik yapılmasına karşı çıktı.

Setler sırasız kalır. (Neden? Kullanım şekilleri farklı. Ayrıca, farklı uygulamalar.)

- Guido van Rossum

Kümeler, kampanya siparişini korumak için uygun olmayan farklı bir algoritma kullanır. Set-to-set işlemleri, sipariş gerekiyorsa esnekliklerini ve optimizasyonlarını kaybeder. Küme matematiği sıralı olmayan kümeler olarak tanımlanır. Kısacası, set siparişi yakın gelecekte değil.

- Raymond Hettinger

3.7 için setlerin sıkıştırılıp sıkıştırılmayacağı ve neden karar verildiğine ilişkin cevaplar hakkında ayrıntılı bir tartışma, python-dev posta listelerinde bulunabilir.

Özetle, ana hususlar kullanım şekillerinin farklı olmasıdır (** kwargs gibi ekleme sipariş dikmeleri faydalıdır , kümeler için daha azdır), sıkıştırma kümeleri için alan tasarrufu daha az önemlidir (çünkü yalnızca anahtar ve karma dizisi vardır) tuşların, karmaların ve değerlerin aksine yoğunlaştırma) ve setlerde yukarıda belirtilen doğrusal problama optimizasyonu kompakt bir uygulama ile uyumsuzdur.

Raymond'un aşağıda en önemli noktaları kapsayan gönderisini yeniden oluşturacağım.

14 Eylül 2016, 15:50, Eric Snow şunu yazdı:

Sonra, setlere de aynısını yapacağım.

Yanlış anlamadığım sürece, Raymond sette benzer bir değişiklik yapmaya karşıydı.

Doğru. İşte insanlar vahşi çalışmaya başlamadan önce konu hakkında birkaç düşünce.

  • Kompakt dikte için, alan tasarrufu, endeksler tarafından tüketilen ek alan ve anahtar / değer / hash dizilerinin aşırı konumlandırılması, anahtar / değer / hash dizilerinin gelişmiş yoğunluğu ile dengelenmekten daha fazla olan net bir kazançtı. Ancak kümeler için net çok daha az elverişliydi, çünkü hala endekslere ve aşırı konumlandırmaya ihtiyacımız var, ancak alan maliyetini sadece üç diziden sadece ikisini yoğunlaştırarak dengeleyebiliriz. Diğer bir deyişle, anahtarlar, değerler ve karmalar için yer harcadığınızda sıkıştırma yapmak daha mantıklıdır. Eğer bu üçünden birini kaybederseniz, zorlayıcı olmaktan çıkıyor.

  • Setler için kullanım şekli dikteden farklıdır. İlki daha fazla hit ya da özledim aramaları var. İkincisi daha az eksik anahtar aramasına sahip olma eğilimindedir. Ayrıca, set-to-set işlemleri için yapılan bazı optimizasyonlar, performansı etkilemeden set sırasını korumayı zorlaştırır.

  • Ayarlanan performansı iyileştirmek için alternatif bir yol izledim. Sıkıştırmak yerine (çok fazla alan kazanmak değildi ve ek bir dolaylamanın maliyetine katlandı), çarpışmaların maliyetini azaltmak ve önbellek performansını artırmak için doğrusal problama ekledim. Bu gelişme sözlükler için savunduğum sıkıştırma yaklaşımıyla uyumsuz.

  • Şimdilik, sözlükler üzerindeki sipariş yan etkisi garanti edilmemektedir, bu nedenle setlerin de sipariş edilmesinde ısrar etmeye başlamak erken. Dokümanlar zaten bir OrderedSet ( https://code.activestate.com/recipes/576694/ ) oluşturmak için bir tarife bağlanıyor, ancak alım neredeyse sıfır gibi görünüyor. Ayrıca, Eric Snow bize hızlı bir OrderedDict verdiğine göre, MutableSet ve OrderedDict'ten bir OrderedSet oluşturmak her zamankinden daha kolay, ancak yine de gerçek bir ilgi görmedim çünkü tipik set-set veri analizi gerçekte değil sipariş ihtiyacı veya bakım. Benzer şekilde, hızlı üyelik testlerinin birincil kullanımı düzen agnostiktir.

  • Bununla birlikte, PyPI'ye alternatif set uygulamaları eklemek için yer olduğunu düşünüyorum. Özellikle, set-to-set işlemlerin tüm anahtar aralıkları karşılaştırılarak hızlandırılabileceği verilerle ilgili bazı ilginç özel durumlar vardır (bkz. Https://code.activestate.com/recipes/230113-implementation-of- başlangıç ​​noktası için kümeler kullanarak sıralama listeleri ). IIRC, PyPI zaten set benzeri çiçek filtreleri ve guguk karma için koda sahiptir.

  • Python çekirdeğinde büyük bir kod bloğunun kabul edilmesinin heyecan verici olduğunu, ancak garanti edilmediğinden emin olmadıkça, taşkınların diğer veri türlerinin daha büyük yeniden yazmalarına katılmaya açılmaması gerektiğini anlıyorum.

- Raymond Hettinger

Gönderen [Python-Dev] Python 3.6 dict kompakt hale gelir ve özel bir versiyon alır; ve anahtar kelimeler sipariş edildi , Eylül 2016.


2

Tartışmalar

Sorunuz almanca ve çok uzun zaman önce python-devs üzerinde yoğun bir şekilde tartışıldı . R. Hettinger bu konudaki rasyonların bir listesini paylaştı . Sorunun durumu, bu ayrıntılı yanıttan kısa bir süre sonra şimdi açık uçlu görünüyor T. Peters'in .

Kısacası, ekleme talimatını koruyan modern diktelerin uygulanması benzersizdir ve setlerle uygun görülmemektedir. Özellikle, dikmeler Python'u çalıştırmak için her yerde kullanılır (örneğin __dict__nesnelerin ad alanlarında). Modern diktenin arkasındaki ana motivasyon, boyutu azaltmak ve Python'u genel olarak daha bellek verimli hale getirmekti. Buna karşılık, setler Python'un çekirdeğindeki diktelerden daha az yaygındır ve bu nedenle böyle bir yeniden düzenlemeyi reddeder. Ayrıca bkz. R. Hettinger'in modern diksiyon uygulaması hakkındaki konuşması .


Perspektifler

Python'daki kümelerin düzensiz doğası, matematiksel kümelerin davranışına paraleldir . Sipariş garanti edilmez.

İlgili matematiksel kavram sıralanmamıştır ve düzen gibi empoze etmek tuhaf olacaktır - R. Hettinger

Eğer herhangi bir sipariş Python kümelerine tanıtıldı, o zaman bu davranış tamamen ayrı matematiksel yapının, yani sıralı bir dizi (veya Oset) uygun olur. Osets matematikte, özellikle kombinatorikte ayrı bir rol oynar. Osets'in pratik bir uygulaması çanların değiştirilmesinde .

Sırasız kümelere sahip olmak, en modern matematiği birleştiren çok genel ve her yerde bulunan bir veri yapısı ile tutarlıdır, yani Set Teorisi . Gönderirim, Python'daki sırasız setlere sahip olmak iyidir.

Bu konuyla ilgili genişleyen ilgili gönderilere de bakın:

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.