파이썬 초기 버전부터 객체 간 비교가 가능했습니다. 객체에 대해 "크다" 또는 "같다"는 의미를 설명하기 위해 특별한 비교 메서드(eq, ne, lt, le, gt, ge)가 만들어졌습니다. PEP 207(Python 2.1+)의 출현으로 프로그래머가 비교 동작을 명시적으로 제어할 수 있도록 단일 비교 프로토콜이 구현되었습니다.
기본 타입(int, str)은 "값에 따라" 비교되지만, 사용자 정의 클래스는 기본적으로 "아이덴티티에 따라" 비교됩니다(is). 마법의 비교 메서드를 구현하지 않거나 잘못 구현하면, 객체 비교는 컬렉션, 정렬, set 및 dict 사용 시 예상치 못한 동작을 하거나 때때로 타입 오류로 이어집니다.
클래스에서 비교 메서드를 명시적으로 정의해야 합니다. 가장 자주 구현하는 것은 eq(같음)와 lt(작음)이며, 나머지 메서드는 functools.total_ordering 데코레이터를 사용하여 자동으로 얻을 수 있습니다.
코드 예시:
from functools import total_ordering @total_ordering class Point: def __init__(self, x, y): self.x = x self.y = y def __eq__(self, other): if not isinstance(other, Point): return NotImplemented return self.x == other.x and self.y == other.y def __lt__(self, other): if not isinstance(other, Point): return NotImplemented return (self.x, self.y) < (other.x, other.y) # 사용 예: p1 = Point(1, 2) p2 = Point(1, 3) print(p1 < p2) # True print(p1 == p2) # False
주요 특징:
단 하나의 비교 메서드(eq 또는 lt)만 구현하면 모든 것이 작동하나요?
아니요. __eq__만 구현하면 동등성 비교는 올바르게 동작하지만, <, >, <=, >= 연산자는 기본적으로 객체 아이디를 비교하여 동작합니다. 전체 동작을 위해서는 충분한 메서드 세트를 구현하거나 functools.total_ordering을 사용해야 합니다.
왜 compare(x, y)가 다른 언어처럼 파이썬에 존재하지 않나요?
파이썬은 각 연산자에 대한 특별한 "마법" 메서드 개념을 상속받았고, cmp 함수는 Python 3부터 제거되었습니다. 객체의 일반 비교에는 풍부한 비교 메서드(lt, eq 등)를 사용하고, 정렬에는 sort/sorted 함수의 key 매개변수를 사용합니다.
지원하는 메서드가 없는 타입과 객체를 비교하면 어떻게 되나요?
eq 또는 다른 메서드에서 지원하지 않는 타입에 대해 NotImplemented를 반환하면, 파이썬은 자동으로 두 번째 피연산자의 반대 메서드를 시도하거나 False를 반환합니다. 이러한 경우를 처리하지 않으면 TypeError가 발생하거나 전혀 잘못된 동작이 발생할 수 있습니다.
코드 예시:
class Foo: def __eq__(self, other): return NotImplemented class Bar: pass print(Foo() == Bar()) # False (Bar.__eq__를 통한 시도)
개발자가 User 클래스를 만들고 hash 없이 __eq__만 구현하여 사용자가 이메일로 동등하게 판별되도록 했습니다. 이후 User 객체를 set에 사용하려고 하거나 사전의 키로 사용하려 했습니다.
장점:
단점:
프로그래머는 @total_ordering을 사용하고 eq 및 __lt__를 타입 검사를 추가하여 구현하며, 클래스가 변경 불가능할 경우 __hash__를 추가합니다. 객체가 올바르게 비교되고 정렬되며 사전 키로 작동합니다.
장점:
단점: