__cmp__ 대신 __lt__
Python 2.x에는 비교 연산자를 오버로드하는 두 가지 방법 __cmp__
또는 __lt__
. 풍부한 비교 과부하가 선호된다고하지만 이것이 왜 그런가요?
풍부한 비교 연산자는 각각을 구현하는 것이 더 간단하지만 거의 동일한 논리로 여러 연산자를 구현해야합니다. 그러나 내장 cmp
및 튜플 순서를 사용할 수 있다면 __cmp__
매우 간단 해지고 모든 비교를 수행 할 수 있습니다 .
class A(object):
def __init__(self, name, age, other):
self.name = name
self.age = age
self.other = other
def __cmp__(self, other):
assert isinstance(other, A) # assumption for this example
return cmp((self.name, self.age, self.other),
(other.name, other.age, other.other))
이 단순함은 풍부한 비교 6 (!)을 모두 오버로드하는 것보다 훨씬 더 내 요구를 충족하는 것 같습니다. (그러나 "교체 된 주장"/ 반영된 행동에 의존한다면 "단지"4로 낮출 수 있지만, 내 겸손한 의견으로는 순전히 합병증이 증가합니다.)
과부하 만 발생하는 경우 알아야 할 예상치 못한 함정이 __cmp__
있습니까?
나는 이해 <
, <=
, ==
, 등 사업자가 다른 목적을 위해 오버로드 할 수 있으며, 원하는 개체에게 그들이 반환 할 수 있습니다. 나는 그 접근 방식의 장점에 대해 묻는 것이 아니라 숫자를 의미하는 것과 같은 의미에서 비교를 위해 이러한 연산자를 사용할 때의 차이점에 대해서만 묻습니다.
업데이트 : 크리스토퍼으로 지적 , cmp
3.x에서에서 사라지고있다 위와 같이 쉽게 비교를 구현할 수있는 대안이 __cmp__
있습니까?
예, 예 __lt__
를 들어 mixin 클래스 (또는 메타 클래스, 또는 취향이 그런 식으로 실행되는 경우 클래스 데코레이터)의 관점에서 모든 것을 구현하는 것은 쉽습니다 .
예를 들면 :
class ComparableMixin:
def __eq__(self, other):
return not self<other and not other<self
def __ne__(self, other):
return self<other or other<self
def __gt__(self, other):
return other<self
def __ge__(self, other):
return not self<other
def __le__(self, other):
return not other<self
이제 클래스는 __lt__
ComparableMixin에서 상속을 정의 하고 곱할 수 있습니다 (필요한 다른베이스가있는 경우). 클래스 데코레이터는 데코 레이트하는 새 클래스의 속성과 유사한 함수를 삽입하기 만하면 매우 유사 할 것입니다 (결과는 메모리 측면에서 동일한 분 비용으로 런타임시 미세하게 더 빠를 수 있음).
클래스가 구현하는 몇 가지 특히 빠른 방법 (예)가있는 경우 물론, __eq__
그리고 __ne__
, 그것은 믹스 인의 버전 (경우에 즉, 예를 들어, 사용하지 않도록 직접 정의해야합니다 dict
- 사실) __ne__
도 용이하게 정의 될 수있다 다음과 같이 :
def __ne__(self, other):
return not self == other
그러나 위의 코드에서 나는 <
;-) 만 사용하는 즐거운 대칭을 유지하고 싶었습니다 . 왜에 관해서는 __cmp__
우리가 있기 때문에, 가야했다 했다 가 __lt__
친구, 왜, 주위 정확히 같은 일을 할 수있는 다른 방법을 다른 유지? 모든 Python 런타임 (Classic, Jython, IronPython, PyPy, ...)에서 매우 무겁습니다. 이라는 코드 확실히 버그가되지 않습니다이없는 코드입니다 - 거기에이 작업을 수행하기 위해 이상적으로 하나의 확실한 방법이 될한다고 그 파이썬의 원리는 (C는의 "성령 C의"절에 같은 원리를 가지고 어디서 ISO 표준, btw).
This doesn't mean we go out of our way to prohibit things (e.g., near-equivalence between mixins and class decorators for some uses), but it definitely does mean that we don't like to carry around code in the compilers and/or runtimes that redundantly exists just to support multiple equivalent approaches to perform exactly the same task.
Further edit: there's actually an even better way to provide comparison AND hashing for many classes, including that in the question -- a __key__
method, as I mentioned on my comment to the question. Since I never got around to writing the PEP for it, you must currently implement it with a Mixin (&c) if you like it:
class KeyedMixin:
def __lt__(self, other):
return self.__key__() < other.__key__()
# and so on for other comparators, as above, plus:
def __hash__(self):
return hash(self.__key__())
It's a very common case for an instance's comparisons with other instances to boil down to comparing a tuple for each with a few fields -- and then, hashing should be implemented on exactly the same basis. The __key__
special method addresses that need directly.
To simplify this case there's a class decorator in Python 2.7+/3.2+, functools.total_ordering, that can be used to implement what Alex suggests. Example from the docs:
@total_ordering
class Student:
def __eq__(self, other):
return ((self.lastname.lower(), self.firstname.lower()) ==
(other.lastname.lower(), other.firstname.lower()))
def __lt__(self, other):
return ((self.lastname.lower(), self.firstname.lower()) <
(other.lastname.lower(), other.firstname.lower()))
This is covered by PEP 207 - Rich Comparisons
Also, __cmp__
goes away in python 3.0. ( Note that it is not present on http://docs.python.org/3.0/reference/datamodel.html but it IS on http://docs.python.org/2.7/reference/datamodel.html )
Inspired by Alex Martelli's ComparableMixin
& KeyedMixin
answers, I came up with the following mixin. It allows you to implement a single _compare_to()
method, which uses key-based comparisons similar to KeyedMixin
, but allows your class to pick the most efficient comparison key based on the type of other
. (Note that this mixin doesn't help much for objects which can be tested for equality but not order).
class ComparableMixin(object):
"""mixin which implements rich comparison operators in terms of a single _compare_to() helper"""
def _compare_to(self, other):
"""return keys to compare self to other.
if self and other are comparable, this function
should return ``(self key, other key)``.
if they aren't, it should return ``None`` instead.
"""
raise NotImplementedError("_compare_to() must be implemented by subclass")
def __eq__(self, other):
keys = self._compare_to(other)
return keys[0] == keys[1] if keys else NotImplemented
def __ne__(self, other):
return not self == other
def __lt__(self, other):
keys = self._compare_to(other)
return keys[0] < keys[1] if keys else NotImplemented
def __le__(self, other):
keys = self._compare_to(other)
return keys[0] <= keys[1] if keys else NotImplemented
def __gt__(self, other):
keys = self._compare_to(other)
return keys[0] > keys[1] if keys else NotImplemented
def __ge__(self, other):
keys = self._compare_to(other)
return keys[0] >= keys[1] if keys else NotImplemented
(Edited 6/17/17 to take comments into account.)
I tried out the comparable mixin answer above. I ran into trouble with "None". Here is a modified version that handles equality comparisons with "None". (I saw no reason to bother with inequality comparisons with None as lacking semantics):
class ComparableMixin(object):
def __eq__(self, other):
if not isinstance(other, type(self)):
return NotImplemented
else:
return not self<other and not other<self
def __ne__(self, other):
return not __eq__(self, other)
def __gt__(self, other):
if not isinstance(other, type(self)):
return NotImplemented
else:
return other<self
def __ge__(self, other):
if not isinstance(other, type(self)):
return NotImplemented
else:
return not self<other
def __le__(self, other):
if not isinstance(other, type(self)):
return NotImplemented
else:
return not other<self
참고URL : https://stackoverflow.com/questions/1061283/lt-instead-of-cmp
'developer tip' 카테고리의 다른 글
virtualenv는 어디에서 만들어야합니까? (0) | 2020.08.27 |
---|---|
트위터 부트 스트랩 내비게이션 바의“아이콘 바” (0) | 2020.08.27 |
R data.frame에서 행을 가져 오는 방법 (0) | 2020.08.27 |
Tomcat 시작 로그-심각 : 오류 filterStart 스택 추적을 얻는 방법? (0) | 2020.08.26 |
데이터 프레임의 구분 기호에서 열 분할 (0) | 2020.08.26 |