파이썬 사용자 정의 클래스를 정렬 가능하고 해시 가능하게 만들기


82

파이썬에서 사용자 정의 클래스를 정렬 가능 및 / 또는 해시 가능하게 만들 때 어떤 메서드를 재정의 / 구현해야합니까?

주의해야 할 점은 무엇입니까?

dir({})인터프리터에 입력 하여 내장 딕셔너리에 대한 메소드 목록을 얻습니다. 그중 일부를 구현해야한다고 가정합니다.

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

Python2와 달리 Python3에 대해 구현해야하는 메서드에 차이가 있습니까?


3
좋은 토론 : stackoverflow.com/q/1061283/641766 . Python 2.x와 3.x의 차이점 __cmp__은 제거되었습니다.
zeekay 2011-08-22

답변:


88

나는 이것을 다른 답변에 대한 의견으로 거의 게시했지만 실제로는 그 자체로 답변입니다.

항목을 정렬 가능하게 만들려면 __lt__. 이것이 내장 정렬에서 사용되는 유일한 방법입니다.

다른 비교는 또는 functools.total_ordering클래스와 함께 비교 연산자를 실제로 사용하려는 경우에만 필요합니다.

항목을 해시 할 수 있도록하려면 __hash__다른 사람들이 언급 한대로 구현 합니다. 또한 __eq__호환 가능한 방식으로 구현 해야합니다. 동일한 항목은 동일하게 해시해야합니다.


그래서 잘못된 구현으로 __lt__인해 파이썬이 예기치 않게 정렬 될 수 있습니까? (예 : if x .__ lt __ (y) 및 y .__ lt __ (x))
Matt Fenwick

3
"예측 불가능"에 대해 모르겠습니다. 정확히 동일한 입력을 제공하면 일관성이있을 수 있지만 입력 순서가 다르면 항목이 다른 순서로 표시 될 수 있습니다. 예, 정렬에 사용 된 비교를 부적절하게 구현하면 Python이 부적절하게 정렬됩니다. __key__인스턴스를 튜플으로 변환 한 다음 __lt__( self.__key__() < other.__key__()) 및 __hash__( hash(self.__key__())) 모두 사용 하도록하는 함수를 권장 합니다.
agf 2011-08-24

19

Python 2와 3에는 차이가 없습니다.

정렬 가능성 :

비교 방법을 정의해야합니다. 이렇게하면 항목을 정렬 할 수 있습니다. 일반적으로 __cmp__().

나는 보통 functools.total_ordering 데코레이터를 사용합니다.

functools.total_ordering (cls) 하나 이상의 풍부한 비교 순서 지정 방법을 정의하는 클래스가 주어지면이 클래스 데코레이터가 나머지를 제공합니다. 이렇게하면 가능한 모든 풍부한 비교 연산을 지정하는 데 드는 노력이 간소화됩니다.

클래스 중 하나 정의해야합니다 __lt__(), __le__(), __gt__(), 또는 __ge__(). 또한 클래스는 __eq__()메서드를 제공해야합니다 .

비교 방법에 부작용이 없는지주의해야합니다. (객체의 값을 변경)

해싱의 경우 :

__hash__()메소드 를 구현해야합니다 . 가장 좋은 방법은을 반환하는 hash(repr(self))것이므로 해시가 고유 할 것입니다.


functools.total_ordering설명서 의 예는 여기를 참조 하십시오 .
Evgeni Sergeev

3

개체를 정렬 가능하게 표시하는 방법에는 몇 가지가 있습니다. 첫 번째-함수 세트로 정의 된 풍부한 비교 :

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

또한 하나의 함수 만 정의 할 수도 있습니다.

object.__cmp__(self, other)

그리고 사용자 정의 __hash__함수 를 정의하려면 마지막을 정의해야합니다 . 문서를 참조하십시오 .


6
Python 3에서 "[...] __cmp__()특별한 메서드는 더 이상 지원되지 않습니다." 여기 에서 관련 섹션을 참조하십시오 .
Evgeni Sergeev

-3

구현 __lt__(self,other)방법은 클래스를 정렬 가능하게 만드는 대답입니다.
내장 메소드 sorted(iterable)뿐만 아니라 heapq모듈을 통한 우선 순위 큐에도 사용할 수 있습니다 .

게다가 저는 파이썬의 디자인이 마음에 들지 않아서 많은 '__ge__', '__gt__', '__le__', '__lt__', '__ne__'방법이 전혀 직관적이지 않습니다 !
대조적으로 Java Interface Comparable<T> ( java doc 참조 )는이 객체가 직접적이고 친숙한 지정된 객체보다 작거나 같거나 크므로 음의 정수, 0 또는 양의 정수를 반환합니다 !


9
대부분의 답변은 귀하의 의견을 포함합니다 (답변의 일부가 아니어야 함).
skyking apr

@skyking ...이 특정 답변의 의견에 동의하지는 않지만 (질문과 관련된 조사되고 유용한 데이터를 포함한) 의견이 매우 가치 있다고 생각합니다. 이 의견 답변의 오류는 관련 데이터로 의견을 뒷받침하지 않습니다. 그러나 선호도를 이해하면 사람들이 결정을 내리는 데 도움이되므로 매우 유용합니다. 여기에서는 작성자의 선호도에 따라 코드를 작성하는 비단뱀적인 방법을 설명하는 유용하고 실행 가능한 파이썬 코드가 없기 때문에 답이 잘못 형성되었습니다.
Andrew
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.