이 간단한 문제를 고려하십시오.
class Number:
def __init__(self, number):
self.number = number
n1 = Number(1)
n2 = Number(1)
n1 == n2 # False -- oops
따라서 Python은 기본적으로 비교 작업에 객체 식별자를 사용합니다.
id(n1) # 140400634555856
id(n2) # 140400634555920
__eq__
함수를 재정의하면 문제가 해결되는 것 같습니다.
def __eq__(self, other):
"""Overrides the default implementation"""
if isinstance(other, Number):
return self.number == other.number
return False
n1 == n2 # True
n1 != n2 # True in Python 2 -- oops, False in Python 3
에서 파이썬이 항상 우선 기억 __ne__
은 AS뿐만 아니라, 기능을 문서 상태 :
비교 연산자 사이에는 내재 된 관계가 없습니다. 진실은 x==y
그것이 x!=y
거짓 임을 암시하지 않습니다 . 따라서을 정의 할 때 연산자가 예상대로 작동하도록 __eq__()
정의 __ne__()
해야합니다.
def __ne__(self, other):
"""Overrides the default implementation (unnecessary in Python 3)"""
return not self.__eq__(other)
n1 == n2 # True
n1 != n2 # False
파이썬 3 에서는 문서가 다음 과 같이 더 이상 필요하지 않습니다 .
기본적으로 결과가 아닌 경우 결과를 __ne__()
위임 __eq__()
하고 반전시킵니다 NotImplemented
. 비교 연산자간에 다른 암시 적 관계는 없습니다. 예를 들어, 진실이 (x<y or x==y)
암시하지 않습니다 x<=y
.
그러나 이것이 우리의 모든 문제를 해결하는 것은 아닙니다. 서브 클래스를 추가하자 :
class SubNumber(Number):
pass
n3 = SubNumber(1)
n1 == n3 # False for classic-style classes -- oops, True for new-style classes
n3 == n1 # True
n1 != n3 # True for classic-style classes -- oops, False for new-style classes
n3 != n1 # False
참고 : Python 2에는 두 가지 종류의 클래스가 있습니다.
고전적인 스타일 (또는 이전 스타일 않음) 클래스 하지 상속object
과 같이 선언class A:
,class A():
또는class A(B):
어디에서B
고전적인 스타일의 클래스입니다;
상속받은 새로운 스타일의 클래스,또는새로운 스타일의 클래스object
로 선언 된곳. Python 3에는,또는로 선언 된 새로운 스타일의 클래스 만있습니다.class A(object)
class A(B):
B
class A:
class A(object):
class A(B):
클래식 스타일 클래스의 경우 비교 연산은 항상 첫 번째 피연산자의 메소드를 호출하는 반면 새 스타일 클래스 의 경우 피연산자의 순서에 관계없이 항상 서브 클래스 피연산자의 메소드를 호출합니다 .
여기 Number
고전 스타일의 클래스가 있다면 :
n1 == n3
호출 n1.__eq__
;
n3 == n1
호출 n3.__eq__
;
n1 != n3
호출 n1.__ne__
;
n3 != n1
전화 n3.__ne__
.
그리고 Number
새로운 스타일의 클래스 라면 :
- 모두
n1 == n3
와 n3 == n1
전화 n3.__eq__
;
- 모두
n1 != n3
와 n3 != n1
전화 n3.__ne__
.
Python 2 클래식 스타일 클래스 에 대한 ==
and !=
연산자 의 비전 역 문제를 해결하려면 피연산자 유형이 지원되지 않을 때 __eq__
및 __ne__
메소드가 NotImplemented
값을 반환해야합니다 . 문서는 정의 NotImplemented
값을 :
제공된 피연산자에 대한 연산을 구현하지 않으면 숫자 메소드와 리치 비교 메소드가이 값을 리턴 할 수 있습니다. 그런 다음 통역사는 연산자에 따라 반영된 작업이나 다른 대체를 시도합니다. 참 값은 true입니다.
이 경우 연산자는 비교 작업을 다른 피연산자 의 반영된 메서드 에 위임합니다 . 이 문서 는 다음과 같이 반영된 방법을 정의합니다.
이러한 메소드의 교체 된 인수 버전은 없습니다 (왼쪽 인수는 연산을 지원하지 않지만 오른쪽 인수는 지원합니다). 오히려, __lt__()
그리고 __gt__()
서로의 반영이다, __le__()
그리고 __ge__()
서로의 반사하고,
__eq__()
그리고 __ne__()
자신의 반영이다.
결과는 다음과 같습니다.
def __eq__(self, other):
"""Overrides the default implementation"""
if isinstance(other, Number):
return self.number == other.number
return NotImplemented
def __ne__(self, other):
"""Overrides the default implementation (unnecessary in Python 3)"""
x = self.__eq__(other)
if x is NotImplemented:
return NotImplemented
return not x
피연산자가 관련이없는 유형 (상속 없음) 인 경우 및 연산자의 정류 가 필요한 경우 새 스타일 클래스에 대해서도 NotImplemented
값을 반환하는 False
것이 옳은 일 입니다.==
!=
우리는 아직있다? 좀 빠지는. 고유 번호는 몇 개입니까?
len(set([n1, n2, n3])) # 3 -- oops
세트는 객체의 해시를 사용하며 기본적으로 파이썬은 객체 식별자의 해시를 반환합니다. 재정의 해 봅시다 :
def __hash__(self):
"""Overrides the default implementation"""
return hash(tuple(sorted(self.__dict__.items())))
len(set([n1, n2, n3])) # 1
최종 결과는 다음과 같습니다 (확인을 위해 마지막에 어설 션을 추가했습니다).
class Number:
def __init__(self, number):
self.number = number
def __eq__(self, other):
"""Overrides the default implementation"""
if isinstance(other, Number):
return self.number == other.number
return NotImplemented
def __ne__(self, other):
"""Overrides the default implementation (unnecessary in Python 3)"""
x = self.__eq__(other)
if x is not NotImplemented:
return not x
return NotImplemented
def __hash__(self):
"""Overrides the default implementation"""
return hash(tuple(sorted(self.__dict__.items())))
class SubNumber(Number):
pass
n1 = Number(1)
n2 = Number(1)
n3 = SubNumber(1)
n4 = SubNumber(4)
assert n1 == n2
assert n2 == n1
assert not n1 != n2
assert not n2 != n1
assert n1 == n3
assert n3 == n1
assert not n1 != n3
assert not n3 != n1
assert not n1 == n4
assert not n4 == n1
assert n1 != n4
assert n4 != n1
assert len(set([n1, n2, n3, ])) == 1
assert len(set([n1, n2, n3, n4])) == 2
is
객체 ID와 값 비교를 구별 하는 연산자 가 있기 때문에 이것이 분명하다고 생각합니다 .