Bir python kullanıcı tanımlı sınıfı sıralanabilir, karma hale getirilebilir yapma


83

Kullanıcı tanımlı sınıfları python'da sıralanabilir ve / veya karma hale getirilirken hangi yöntemlerin geçersiz kılınması / uygulanması gerekir?

Dikkat edilmesi gerekenler nelerdir?

Ben tip dir({})benim tercüman içine dahili içinde dicts üzerinde yöntemlerinin bir listesini almak için. Bunlardan bazılarının bazı alt kümelerini uygulamam gerektiğini varsayıyorum

['__cmp__', '__eq__', '__ge__', '__gt__', '__hash__', '__le__', '__lt__', '__ne__']

Python2'nin aksine Python3 için hangi yöntemlerin uygulanması gerektiği konusunda bir fark var mı?


3
Burada iyi tartışma: stackoverflow.com/q/1061283/641766 . Python 2.x ve 3.x arasındaki fark __cmp__kaldırılmış olmasıdır.
zeekay

Yanıtlar:


90

Bunu neredeyse diğer cevaplara bir yorum olarak gönderiyordum ama bu gerçekten kendi başına bir cevap.

Öğelerinizi sıralanabilir hale getirmek için, yalnızca uygulaması gerekir __lt__. Yerleşik sıralama tarafından kullanılan tek yöntem budur.

Diğer karşılaştırmalar veya functools.total_orderingyalnızca karşılaştırma işleçlerini sınıfınızla gerçekten kullanmak istiyorsanız gereklidir.

Öğelerinizi hashable hale getirmek için __hash__diğerlerinin belirttiği gibi uygulayın . Ayrıca __eq__uyumlu bir şekilde uygulamalısınız - eşdeğer öğeler aynı hash uygulamalıdır.


bu yüzden kötü bir uygulama __lt__python'un tahmin edilemeyen bir şekilde sıralanmasına neden olabilir mi? (örneğin, eğer x .__ lt __ (y) ve y .__ lt __ (x) ise)
Matt Fenwick

3
"Tahmin edilemeyecek şekilde" hakkında bir bilgim yok, tam olarak aynı girdiyle beslenirse tutarlı olur, ancak farklı bir girdi sırası, farklı öğelerin farklı bir sırada olmasına neden olabilir. Evet, sıralama için kullanılan karşılaştırmayı yanlış uygularsanız, Python yanlış bir şekilde sıralayacaktır. Ben tavsiye ederim __key__bir demet haline örneğini döner işlevi, o zaman sadece var hem __lt__( self.__key__() < other.__key__()) ve __hash__( hash(self.__key__())) kullanımı söyledi.
agf

21

Python 2 ile 3 arasında herhangi bir fark yoktur.

Sıralanabilirlik için:

Karşılaştırma yöntemlerini tanımlamalısınız. Bu, öğelerinizi sıralanabilir hale getirir. Genelde tercih etmemelisiniz __cmp__().

Genellikle functools.total_ordering decorator kullanıyorum.

functools.total_ordering (cls) Bir veya daha fazla zengin karşılaştırma sıralama yöntemini tanımlayan bir sınıf verildiğinde, bu sınıf dekoratörü gerisini sağlar. Bu, olası tüm zengin karşılaştırma işlemlerinin belirtilmesiyle ilgili çabayı basitleştirir:

Sınıf biri tanımlamalıdır __lt__(), __le__(), __gt__()ya da __ge__(). Ek olarak, sınıf bir __eq__()yöntem sağlamalıdır .

Karşılaştırma yöntemlerinizin herhangi bir yan etkisi olmamasına dikkat etmelisiniz. (nesnenin herhangi bir değerini değiştirin)

Hashing için:

__hash__()Yöntemi uygulamalısınız . Bence en iyi yol geri dönmektir hash(repr(self)), bu yüzden hash'iniz benzersiz olacaktır.


functools.total_orderingBelgelerden bir örnek için buraya bakın .
Evgeni Sergeev

3

Nesnenizi sıralanabilir olarak işaretlemenin birkaç yolu vardır. Birinci - zengin karşılaştırma, bir dizi işlevle tanımlanır:

object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)

Ayrıca yalnızca bir işlev tanımlamak da mümkündür:

object.__cmp__(self, other)

Ve özel __hash__fonksiyon tanımlamak istiyorsanız sonuncusu tanımlanmalıdır . Belgeye bakın .


6
Python 3'te, "[...] __cmp__()özel yöntem artık desteklenmemektedir", buradaki ilgili bölüme bakın .
Evgeni Sergeev

-3

Uygulama __lt__(self,other)yöntemi, sınıfınızı sıralanabilir hale getirmenin cevabıdır.
Sadece yerleşik yöntem için değil sorted(iterable), aynı zamanda heapqmodül aracılığıyla öncelik kuyruğu için de kullanılabilir .

Ek olarak, python'un tasarımını sevmiyorum, pek çok '__ge__', '__gt__', '__le__', '__lt__', '__ne__'yöntem hiç de sezgisel değil !
Bunun aksine, Java'nın Interface Comparable<T> ( java belgesine bakın ), bu nesne belirtilen nesneden küçük, ona eşit veya daha büyük olduğu için negatif bir tamsayı, sıfır veya pozitif bir tamsayı döndürür, bu da doğrudan ve dostudur !


9
Cevabınızın çoğu fikrinizi kapsar (cevabın bir parçası olmamalıdır).
2018

@skyking ... Bu cevabın verdiği fikirlere katılmıyorum ama bu fikrin (soruyla ilgili araştırılmış ve faydalı verilerle) çok değerli olduğuna inanıyorum. Bu görüş yanıtındaki hata, görüşü ilgili verilerle desteklemiyor. Ancak tercihleri ​​anlamak, insanların karar vermesine yardımcı olur ve bu nedenle çok faydalıdır. Burada, cevap kötü biçimlendirilmiş çünkü yazarın tercihlerine göre kodlamanın pitonik bir yolunu gösterecek yararlı ve eyleme geçirilebilir bir python kodu yok.
Andrew
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.