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


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.