__ne__을 __eq__의 부정으로 구현해야 합니까?
는 하고 싶은 이 있습니다.__eq__
방법. 내가 그 일을 무시해야 한다는 것이 말이 되는 것 같습니다를 무시하는 게 할 것 요.__ne__
방법도. 구현해야 합니까를 해야 요?__ne__
__eq__
아니면 나쁜 생각입니까?
class A:
def __init__(self, state):
self.state = state
def __eq__(self, other):
return self.state == other.state
def __ne__(self, other):
return not self.__eq__(other)
을 요?
__ne__()
n__eq__
?
단답형: 해야 한다면 구현하지 마십시오를 사용하세요. 하지만 필요한 경우 사용하십시오.==
,것은 아니다.__eq__
파이썬 3에서는.!=
입니다.==
.다를은하십시오.__ne__
더 를 에 대해 을 제시하지
일반적으로 Python 3 전용 코드의 경우 기본 제공 개체의 경우와 같이 상위 구현을 무색하게 할 필요가 없는 한 작성하지 마십시오.
Raymond Hettinger가 한 말을 명심해야 합니다.
__ne__
다에서 자동으로 .__eq__
만일의 경우에만__ne__
아직 슈퍼클래스에 정의되어 있지 않습니다.기본 제공에서 상속하는 경우 둘 다 무시하는 것이 좋습니다.
Python 2에서 작동하려면 Python 2의 권장 사항을 따라가면 Python 3에서 작동합니다.
는 다른 2 에서인 를 __ne__
에서로 ==
__eq__
를 들면 .
class A(object):
def __eq__(self, other):
return self.value == other.value
def __ne__(self, other):
return not self == other # NOT `return not self.__eq__(other)`
증거 참조
-
__ne__()
n__eq__
그리고. - 하지 않는
__ne__
2 파이썬 에서.
는 아래 데모에서 잘못된 동작을 제공합니다.
긴 대답
파이썬 2의 설명서에는 다음과 같이 나와 있습니다.
비교 연산자 간에 내포된 관계가 없습니다.실의 .
x==y
다를 는 않습니다.x!=y
거짓입니다.따라서, 다음과 같이 정의할 때__eq__()
.__ne__()
조작자가 예상대로 행동하도록 하기 위해서입니다.
입니다.__ne__
__eq__
는 일관된 할 수 , .
이 문서의 이 섹션은 Python 3용으로 업데이트되었습니다.
으로,
__ne__()
단__eq__()
시킵니다.NotImplemented
.
"새로운 기능" 섹션에서는 이러한 동작이 변경되었음을 확인할 수 있습니다.
!=
다의 합니다.==
,~하지 않는 한==
sNotImplemented
.
구현을 위해, 우리는 연산자를 사용하는 대신에__eq__
self.__eq__(other)
NotImplemented
은 확인된 에 대해입니다를 확인할 것입니다.other.__eq__(self)
설명서에서:
NotImplemented
이 유형에는 단일 값이 있습니다.이 값을 가진 개체가 하나 있습니다. 제공 다를(를) .
NotImplemented
메소드는 된 피연산자에 이 할 수 있습니다 숫자 메서드와 리치 비교 메서드는 제공된 피연산자에 대한 연산을 구현하지 않을 경우 이 값을 반환할 수 있습니다. 반사 (그러면 인터프리터는 연산자에 따라 반영된 연산이나 다른 폴백을 시도합니다.)그것의 진실한 가치는 진실입니다.
가 합니다.other
이며인를 사용합니다.other
의 경우 의)(:<
,<=
,>=
그리고.>
). 만약NotImplemented
를 반환하고, 반대 메서드를 사용합니다. (같은 메서드를 두 번 확인하지 않습니다.)사용.==
연산자를 사용하면 이 논리가 실행됩니다.
기대들
으로, 를 .__ne__
클래스의 사용자는 다음 함수가 A의 모든 인스턴스에 대해 동일하다고 예상하기 때문에 동일성 검사의 관점에서 볼 수 있습니다.
def negation_of_equals(inst1, inst2):
"""always should return same as not_equals(inst1, inst2)"""
return not inst1 == inst2
def not_equals(inst1, inst2):
"""always should return same as negation_of_equals(inst1, inst2)"""
return inst1 != inst2
즉, 위의 두 함수 모두 항상 동일한 결과를 반환해야 합니다.하지만 이것은 프로그래머에게 달려있습니다.
정의 시 치 못한 동작 __ne__
에 기반을 둔__eq__
:
먼저 설정:
class BaseEquatable(object):
def __init__(self, x):
self.x = x
def __eq__(self, other):
return isinstance(other, BaseEquatable) and self.x == other.x
class ComparableWrong(BaseEquatable):
def __ne__(self, other):
return not self.__eq__(other)
class ComparableRight(BaseEquatable):
def __ne__(self, other):
return not self == other
class EqMixin(object):
def __eq__(self, other):
"""override Base __eq__ & bounce to other for __eq__, e.g.
if issubclass(type(self), type(other)): # True in this example
"""
return NotImplemented
class ChildComparableWrong(EqMixin, ComparableWrong):
"""__ne__ the wrong way (__eq__ directly)"""
class ChildComparableRight(EqMixin, ComparableRight):
"""__ne__ the right way (uses ==)"""
class ChildComparablePy3(EqMixin, BaseEquatable):
"""No __ne__, only right in Python 3."""
동일하지 않은 인스턴스를 인스턴스화합니다.
right1, right2 = ComparableRight(1), ChildComparableRight(2)
wrong1, wrong2 = ComparableWrong(1), ChildComparableWrong(2)
right_py3_1, right_py3_2 = BaseEquatable(1), ChildComparablePy3(2)
예상 동작:
(참고: 아래 각 주장의 매초가 그 이전 주장과 동일하므로 논리적으로 중복되지만, 하나가 다른 하위 클래스일 때는 순서가 중요하지 않다는 것을 증명하기 위해 포함합니다.)
이 있습니다.__ne__
된으로 하였습니다.==
:
assert not right1 == right2
assert not right2 == right1
assert right1 != right2
assert right2 != right1
Python 3에서 테스트하는 이러한 인스턴스도 올바르게 작동합니다.
assert not right_py3_1 == right_py3_2
assert not right_py3_2 == right_py3_1
assert right_py3_1 != right_py3_2
assert right_py3_2 != right_py3_1
그리고 이것들은 그들이 가지고 있는__ne__
된으로 하였습니다.__eq__
이지만 구현이 -다.
assert not wrong1 == wrong2 # These are contradicted by the
assert not wrong2 == wrong1 # below unexpected behavior!
예기치 않은 동작:
됩니다).not wrong1 == wrong2
).
>>> assert wrong1 != wrong2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
그리고.
>>> assert wrong2 != wrong1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
마__ne__
2썬
는 안 다음과 같이 __ne__
Python 2에서는 다음과 같은 동등한 객체를 볼 수 있습니다.
>>> right_py3_1, right_py3_1child = BaseEquatable(1), ChildComparablePy3(1)
>>> right_py3_1 != right_py3_1child # as evaluated in Python 2!
True
는 이어야 .False
!
파이썬 3 소스
CPython에 구현:__ne__
에 있습니다.
case Py_NE:
/* By default, __ne__() delegates to __eq__() and inverts the result,
unless the latter returns NotImplemented. */
if (Py_TYPE(self)->tp_richcompare == NULL) {
res = Py_NotImplemented;
Py_INCREF(res);
break;
}
res = (*Py_TYPE(self)->tp_richcompare)(self, other, Py_EQ);
if (res != NULL && res != Py_NotImplemented) {
int ok = PyObject_IsTrue(res);
Py_DECREF(res);
if (ok < 0)
res = NULL;
else {
if (ok)
res = Py_False;
else
res = Py_True;
Py_INCREF(res);
}
}
break;
은 ㅇ__ne__
사용하다__eq__
?
3__ne__
사항은 C를 합니다.__eq__
레벨이e이기 때문에==
(PyObject_RichCompare)는 효율성이 떨어지므로 처리해야 합니다.NotImplemented
.
한다면__eq__
음,합니다.==
또한 합니다에서 의 구현 수 . 이를 통해 우리는 낮은 수준의 구현 세부 사항을 피할 수 있습니다.__ne__
.
으로.==
우리의 낮은 수준의 논리를 한 곳에 유지하고, 주소 지정을 피할 수 있게 해줍니다.NotImplemented
인에__ne__
.
는 그 를 도 있습니다.==
돌아올지도 모릅니다NotImplemented
.
는 합니다의 합니다.__eq__
, 동일성을 확인하는 것(아래의 do_rich 비교 및 우리의 증거 참조)
class Foo:
def __ne__(self, other):
return NotImplemented
__eq__ = __ne__
f = Foo()
f2 = Foo()
그리고 비교:
>>> f == f
True
>>> f != f
False
>>> f2 == f
False
>>> f2 != f
True
성능
제 말을 믿지 마세요. 무엇이 더 성능이 좋은지 알아봅시다.
class CLevel:
"Use default logic programmed in C"
class HighLevelPython:
def __ne__(self, other):
return not self == other
class LowLevelPython:
def __ne__(self, other):
equal = self.__eq__(other)
if equal is NotImplemented:
return NotImplemented
return not equal
def c_level():
cl = CLevel()
return lambda: cl != cl
def high_level_python():
hlp = HighLevelPython()
return lambda: hlp != hlp
def low_level_python():
llp = LowLevelPython()
return lambda: llp != llp
다음과 같은 성능 수치가 그 자체를 말해준다고 생각합니다.
>>> import timeit
>>> min(timeit.repeat(c_level()))
0.09377292497083545
>>> min(timeit.repeat(high_level_python()))
0.2654011140111834
>>> min(timeit.repeat(low_level_python()))
0.3378178110579029
은 당신이 그 를 할 때 이 됩니다.low_level_python
그렇지 않으면 C 레벨에서 처리될 파이썬에서 논리를 수행하고 있습니다.
일부 비평가에 대한 대응
다른 답변자는 다음과 같이 말합니다.
방식
not self == other
__ne__
가 올바르지 .를(를) 반환할 수 .NotImplemented
(not NotImplemented
이다.False
및 )__ne__
순위가 수 .__ne__
우선 순위가 없는 메서드입니다.
있는 것.__ne__
돌아오지 않는rNotImplemented
틀리지 않습니다.에,다를 지정을 합니다.NotImplemented
==
합니다.==
정확하게 구현되면 우린 끝입니다
not self == other
3 3 이었습니다.__ne__
메서드는 버그였고 ShadowRanger가 알아차린 대로 2015년 1월 파이썬 3.4에서 수정되었습니다(호 #21408 참조).
그럼 설명을 해보죠.
으로 3 입니다를 __ne__
self.__eq__(other)
sNotImplemented
- 톤)와 함 -다is
만약 그렇다면, 그 역을 반환해야 합니다.클래스 믹스로 작성된 논리는 다음과 같습니다.
class CStyle__ne__:
"""Mixin that provides __ne__ functionality equivalent to
the builtin functionality
"""
def __ne__(self, other):
equal = self.__eq__(other)
if equal is NotImplemented:
return NotImplemented
return not equal
이것은 C 레벨 Python API에 대한 정확성을 위해 필요하며, Python 3에 도입되어 제작되었습니다.
잉여의 relevant__ne__
합니다,되었습니다에 을 포함하여되었습니다.__eq__
또는 ==
- 그리고==
가장 일반적인 방법이었습니다.
대칭성이 중요할까요?
의 집요한 는 합니다를 를 제공합니다.NotImplemented
인에__ne__
하게 여기는 건합니다입니다명확한 예를 들어 논의를 강화해 보겠습니다.
class B:
"""
this class has no __eq__ implementation, but asserts
any instance is not equal to any other object
"""
def __ne__(self, other):
return True
class A:
"This class asserts instances are equivalent to all other objects"
def __eq__(self, other):
return True
>>> A() == B(), B() == A(), A() != B(), B() != A()
(True, True, False, True)
이 를 __ne__
Python
class B:
def __ne__(self, other):
return True
class A:
def __eq__(self, other):
return True
def __ne__(self, other):
result = other.__eq__(self)
if result is NotImplemented:
return NotImplemented
return not result
>>> A() == B(), B() == A(), A() != B(), B() != A()
(True, True, True, True)
분명히 우리는 이 사례들이 동등하고 동등하지 않다는 것을 신경쓰지 말아야 합니다.
저는 대칭성이 합리적인 코드의 가정보다 덜 중요하고 문서의 조언을 따를 것을 제안합니다.
가 A 을 했다면,__eq__
서 내 수 입니다.
class B:
def __ne__(self, other):
return True
class A:
def __eq__(self, other):
return False # <- this boolean changed...
>>> A() == B(), B() == A(), A() != B(), B() != A()
(False, False, True, True)
결론
2 Python 2 합니다를 ==
__ne__
그 이상:
- 맞아요.
- 간단하죠.
- 수행적인
Python 3에서만 C 레벨의 하위 레벨 부정을 사용하십시오. 이는 훨씬 더 단순하고 성능이 뛰어납니다(프로그래머가 정확하다고 판단할 책임이 있지만).
다시 말하지만, 상위 파이썬에서 낮은 수준의 논리를 쓰지 마세요.
네, 괜찮습니다.사실, 문서는 당신이 다음과 같이 정의할 것을 촉구합니다.__ne__
할 때__eq__
:
비교 연산자 간에 내포된 관계가 없습니다.실의 .
x==y
다를 는 않습니다.x!=y
거짓입니다.따라서, 다음과 같이 정의할 때__eq__()
.__ne__()
조작자가 예상대로 행동하도록 하기 위해서입니다.
), 입니다(), 의 입니다.__eq__
, 그러나 항상은 아닙니다.
, 된 Py2/Py3 .__ne__
다음과 같습니다.
import sys
class ...:
...
def __eq__(self, other):
...
if sys.version_info[0] == 2:
def __ne__(self, other):
equal = self.__eq__(other)
return equal if equal is NotImplemented else not equal
이 제품은 모든 제품에 적용됩니다.__eq__
다음을 정의할 수 있습니다.
- 와 다르게
not (self == other)
된 클래스 중가 /않는 와 관련된 하지 않습니다.__ne__
다의 .not
위에__eq__
, 둘 다 예: SQLAlchemy의 ORM,함)__eq__
그리고.__ne__
않음True
아니면False
하려고, ㅇnot
__eq__
입니다.False
, ). - 와 다르게
not self.__eq__(other)
를 통해 로 위임합니다.__ne__
self.__eq__
sNotImplemented
(not self.__eq__(other)
도 있어요,eNotImplemented
이니까할 제.__eq__
할지고__ne__
입니다.False
을 받은 때 두 개체가 하며, 합니다).
에 당신의 ㅇ__eq__
않는NotImplemented
는 ( 없는 returns,은께)합니다,면을 .NotImplemented
때때로, 이것은 그것을 적절하게 처리합니다.import
-python 3에서 에서,__ne__
는 정의되지 않은 상태로 남겨져 파이썬의 네이티브 효율적인 폴백 구현(위의 C 버전)을 대신할 수 있습니다.
이것이 필요한 이유
파이썬 오버로드 규칙
다른 해결책 대신 이렇게 하는 이유에 대한 설명은 다소 난해합니다.파이썬에는 오버로드 연산자와 비교 연산자에 대한 몇 가지 일반적인 규칙이 있습니다.
- 시 ()
LHS OP RHS
.LHS.__op__(RHS)
, 그리고 만약 그것이 돌아온다면,NotImplemented
.RHS.__rop__(LHS)
. :RHS
의 하위 클래스입니다.LHS
의 수업, 그 다음에 테스트.RHS.__rop__(LHS)
첫째. 비교법인의 경우,__eq__
그리고.__ne__
그들 자신의 "롭"입니다 (따라서 테스트 순서는 다음과 같습니다).__ne__
이다.LHS.__ne__(RHS)
,그리고나서RHS.__ne__(LHS)
,RHS
의 하위 클래스입니다.LHS
- "교환된" 연산자의 개념을 제외하고, 연산자들 사이에 묵시적인 관계는 없습니다.를 들어도
LHS.__eq__(RHS)
gTrue
는 .LHS.__ne__(RHS)
sFalse
(실제로 연산자는 부울 값을 반환할 필요도 없습니다. SQLAlchemy와 같은 ORM은 의도적으로 반환하지 않으므로 보다 표현력 있는 쿼리 구문을 허용합니다.)3 기준, 썬 3준,준__ne__
다를 할 수 . 재정의할 수 있습니다.__ne__
__eq__
.
이 기능이 오버로드되는 비교기에 적용되는 방식
연산자를 오버로드하면 두 가지 작업이 수행됩니다.
- 작업을 직접 수행하는 방법을 알고 있는 경우, 비교를 수행하는 방법에 대한 자신의 지식만을 사용하여 수행합니다(작업의 다른 측면에 대해 암묵적 또는 명시적으로 위임하지 마십시오. 수행 방법에 따라 오류 및/또는 무한 재귀가 발생할 수 있습니다.)
- 작업을 직접 수행하는 방법을 모르실 경우 항상 반환하십시오.
NotImplemented
인 파이썬 에 할 수 .
의 .not self.__eq__(other)
def __ne__(self, other):
return not self.__eq__(other)
일 경우 함()__eq__
된 .NotImplemented
. 언제.self.__eq__(other)
sNotImplemented
이다),다.False
,그렇게A() != something_A_knows_nothing_about
sFalse
했어야 할 ,something_A_knows_nothing_about
다의 을 알고 .A
않다면, 돌아왔어야 합니다, , .True
(만약 어느 쪽도 상대방과 비교하는 방법을 모른다면, 그들은 서로 동등하지 않은 것으로 간주됩니다.) 만약A.__eq__
됨()False
NotImplemented
에서)른 입니다"입니다.A
의 의, True
로)A
다)부터일 수 있습니다. 하지만 잘못된 것일 수도 있습니다.something_A_knows_nothing_about
도 something_A_knows_nothing_about
;A() != something_A_knows_nothing_about
s이 됩니다.True
,그렇지만something_A_knows_nothing_about != A()
할 수 있었다False
기타 값 즉 합니다.
의 .not self == other
def __ne__(self, other):
return not self == other
더 미묘합니다.하여가 99%입니다하는 모든 하여 99__ne__
입니다의 입니다.__eq__
.그렇지만not self == other
는 한 두 어깁니다.즉,합니다를 합니다.__ne__
는 논리적으로 반대가 아닙니다.__eq__
중 할 수 를 묻는 질문이 없기 한 번 하지 않습니다. 합니다.__ne__
다른 피연산자가 못해도 말입니다가장 간단한 예는 돌아오는 이상한 수업입니다.False
모든 비교에 있어서, 그러니까.A() == Incomparable()
그리고.A() != Incomparable()
겸용hFalse
한 구현을 합니다.A.__ne__
()NotImplemented
우),입니다).A() != Incomparable()
그리고.Incomparable() != A()
다우,A.__ne__
sNotImplemented
,그리고나서Incomparable.__ne__
sFalse
의 경우 , , Incomparable.__ne__
sFalse
직접).하지만 언제A.__ne__
다로 됩니다.return not self == other
,A() != Incomparable()
sTrue
면)A.__eq__
이 아닌 NotImplemented
,그리고나서Incomparable.__eq__
sFalse
,그리고.A.__ne__
다로 거죠True
), Incomparable() != A()
sFalse.
여기에서 이것의 예시를 볼 수 있습니다.
를 , False
__eq__
그리고.__ne__
좀 이상합니다.했듯이,__eq__
그리고.__ne__
True
/False
에는 SQLlchemy ORM 에는가.True
/False
(부울 문맥으로 평가하면 "진실"이지만, 절대 그런 문맥에서 평가해서는 안 됩니다.)
으로써 __ne__
코드와 같은 종류의 클래스를 적절히 중단합니다.
results = session.query(MyTable).filter(MyTable.fieldname != MyClassWithBadNE())
가 합니다(SQLChemy 하면)를 있다고 하면).MyClassWithBadNE
할 수 있습니다. SQL다가 어댑터를 할 수 있습니다.다.MyClassWithBadNE
함)에게 함),합니다.filter
, 다음 기간 동안:
results = session.query(MyTable).filter(MyClassWithBadNE() != MyTable.fieldname)
결국 지나가게 될 것입니다.filter
aFalse
,self == other
하고,not self == other
를 truthy합니다.False
, .filter
는합니다와 예외를 합니다.False
. 많은 사람들이 이렇게 주장할 것이라고 확신합니다.MyTable.fieldname
비교의 왼쪽에 일관되게 있어야 하며, 일반적인 경우에 이것을 시행할 프로그램적인 이유가 없다는 사실이 남아 있으며, 정확한 일반적인.__ne__
어느 가 있을return not self == other
하나의 배열로만 작동합니다.
구현__ne__
@ShadowRanger__ne__
올바른 것입니다.
def __ne__(self, other):
result = self.__eq__(other)
if result is not NotImplemented:
return not result
return NotImplemented
의 이기도 합니다.__ne__
파이썬 문서에 명시된 바와 같이, 파이썬 3.4 이후:
으로,
__ne__()
단__eq__()
시킵니다.NotImplemented
.
값을 하는 것은 합니다합니다.NotImplemented
되지 않는 다 특수 .__ne__
. 실제로 모든 특수 비교 방법과1 특수 숫자 방법은2 Python 설명서에 명시된 대로 지원되지 않는 피연산자에 대한 값을 반환해야 합니다.
구현되지 않음
이 유형에는 단일 값이 있습니다.이 값을 가진 개체가 하나 있습니다. 제공 다를(를) .
NotImplemented
경우 이 숫자 메서드와 리치 비교 메서드는 제공된 피연산자에 대한 연산을 구현하지 않는 경우 이 값을 반환해야 합니다. 반사 (그러면 인터프리터는 연산자에 따라 반영된 연산이나 다른 폴백을 시도합니다.)그것의 진실한 가치는 진실입니다.
특별한 숫자 방법의 예는 Python 설명서에 나와 있습니다.
class MyIntegral(Integral):
def __add__(self, other):
if isinstance(other, MyIntegral):
return do_my_adding_stuff(self, other)
elif isinstance(other, OtherTypeIKnowAbout):
return do_my_other_adding_stuff(self, other)
else:
return NotImplemented
def __radd__(self, other):
if isinstance(other, MyIntegral):
return do_my_adding_stuff(other, self)
elif isinstance(other, OtherTypeIKnowAbout):
return do_my_other_adding_stuff(other, self)
elif isinstance(other, Integral):
return int(other) + int(self)
elif isinstance(other, Real):
return float(other) + float(self)
elif isinstance(other, Complex):
return complex(other) + complex(self)
else:
return NotImplemented
1 특수 비교 방법:__lt__
,__le__
,__eq__
,__ne__
,__gt__
그리고.__ge__
.
2 특수 숫자 방법:__add__
,__sub__
,__mul__
,__matmul__
,__truediv__
,__floordiv__
,__mod__
,__divmod__
,__pow__
,__lshift__
,__rshift__
,__and__
,__xor__
,__or__
그리고 그들의__r*__
d된__i*__
제자리에 있는 대응물
__ne__
#1
@Falmarri__ne__
올바르지 않습니다.
def __ne__(self, other):
return not self.__eq__(other)
은 입니다 입니다.__ne__
하지 않으므로 NotImplemented
현)not self.__eq__(other)
평가합니다.True
아니면False
하위 인 해서 말입니다.self.__eq__(other)
평가합니다.NotImplemented
라는 표현 bool(NotImplemented)
평가합니다.True
부울 평가()입니다. 값의 부울 평가(Boolean 평가)NotImplemented
비교 연산자 간의 보완 관계를 끊습니다.!=
그리고.==
:
class Correct:
def __ne__(self, other):
result = self.__eq__(other)
if result is not NotImplemented:
return not result
return NotImplemented
class Incorrect:
def __ne__(self, other):
return not self.__eq__(other)
x, y = Correct(), Correct()
assert (x != y) is not (x == y)
x, y = Incorrect(), Incorrect()
assert (x != y) is not (x == y) # AssertionError
__ne__
#2
Hall의 @Aaron Hall__ne__
또한 틀립니다.
def __ne__(self, other):
return not self == other
은 입니다 으로 의존한다는 입니다.__eq__
것을 피연산자.__ne__
하지 않으므로 NotImplemented
현)not self == other
다에 합니다.__eq__
및 합니다.True
아니면False
메서드를 바이패스하면 개체의 상태를 업데이트하는 등의 부작용이 발생할 수 있으므로 메서드를 바이패스하는 것은 올바르지 않습니다.
class Correct:
def __init__(self):
self.state = False
def __ne__(self, other):
self.state = True
result = self.__eq__(other)
if result is not NotImplemented:
return not result
return NotImplemented
class Incorrect:
def __init__(self):
self.state = False
def __ne__(self, other):
self.state = True
return not self == other
x, y = Correct(), Correct()
assert x != y
assert x.state == y.state
x, y = Incorrect(), Incorrect()
assert x != y
assert x.state == y.state # AssertionError
비교 작업의 이해
수학에서 집합 X에 대한 이항 관계 R은 X의2 순서 쌍 (x, y)의 집합입니다.R의 문장 (x, y)는 'x는 y와 R 관련된 것이다'라고 읽으며 xRy로 표시됩니다.
집합 X에 대한 이항 관계 R의 속성:
- X, xRx의 모든 x에 대하여 R은 반사적입니다.
- xRx가 아닌 X의 모든 x에 대해 R은 무굴곡(엄격하다고도 함)입니다.
- X의 모든 x와 y에 대해 대칭이고, xRy이면 yRx입니다.
- X의 모든 x와 y에 대해 xRy와 yRx이면 x = y일 때 R은 대칭이 됩니다.
- X의 모든 x, y, z에 대하여 xRy와 yRz이면 xRz일 때 R은 추이적입니다.
- X, xRy 또는 yRx의 모든 x와 y에 대해 R은 코넥스(합계라고도 함)입니다.
- R은 R이 반사적, 대칭적, 전이적일 때의 동등성 관계입니다.
예를 들면 =.그러나 ≠는 대칭일 뿐입니다. - R은 R이 반사적이고 반대칭적이며 전이적일 때의 차수 관계입니다.
예를 들어, ≤ 및 ≥. - R이 무굴곡, 반대칭 및 전이일 때 R은 엄격한 차수 관계입니다.
예를 들어 < 및 >.하지만 ≠는 무반전적일 뿐입니다.
집합 X에 대한 두 이진 관계 R과 S에 대한 연산:
- R의 반대는 X에 대한 이진 관계 R = {(y, x) | xRy}입니다.
- R의 여집합은 X에 대한 이항 관계 ¬R = {(x, y) | not xRy}입니다.
- R과 S의 결합은 X에 대한 이항 관계 R ∪ S = {(x, y) | xRy 또는 xSy}입니다.
항상 유효한 비교 관계 사이의 관계:
- 2개의 상호보완적 관계: =와 ≠는 서로의 상호보완적인 관계;
- 6개의 역관계: =는 자기 자신의 역, ≠는 자기 자신의 역, <와 >는 서로의 역, ≤와 ≥는 서로의 역,
- 2조합관계: ≤은 <과 =의 결합이고, ≥은 >과 =의 결합입니다.
connex order 관계에만 유효한 비교 관계:
- 4개의 보완관계: <와 ≥은 서로의 보완관계이며 >와 ≤는 서로의 보완관계입니다.
비교 연산자는 Python 에서를 합니다.==
,!=
,<
,>
,<=
,그리고.>=
비교 관계 =, ≠, <, >, ≤, ≥에 해당하는 위의 모든 수학적 속성과 관계가 유지되어야 합니다.
x operator y
에서는 합니다라고 .__operator__
중 다의 .
class X:
def __operator__(self, other):
# implementation
R은 반사적이기 때문에 xRx를 의미하기 때문에, 반사적인 비교 연산은x operator y
(x == y
,x <= y
그리고.x >= y
) x.__operator__(y)
(x.__eq__(y)
,x.__le__(y)
그리고.x.__ge__(y)
을 ) .True
한다면x
그리고.y
즉식하다,하다x is y
합니다.True
. R은 비굴절적이므로 xRx가 아님을 의미하므로 비굴절 비교 연산x operator y
(x != y
,x < y
그리고.x > y
) x.__operator__(y)
(x.__ne__(y)
,x.__lt__(y)
그리고.x.__gt__(y)
을 ) .False
한다면x
그리고.y
즉식하다,하다x is y
합니다.True
인 Python 합니다에 합니다.==
법.__eq__
하지만 놀랍게도 비교 연산자들에게는 고려되지 않았습니다.<=
그리고.>=
특수 비교 법.__le__
그리고.__ge__
인 합니다에 하고 있습니다.!=
법.__ne__
하지만 놀랍게도 비교 연산자들에게는 고려되지 않았습니다.<
그리고.>
특수 비교 법.__lt__
그리고.__gt__
합니다 합니다.TypeError
을 반환합니다합니다).NotImplemented
), 파이썬 문서에서 설명한 바와 같이:
()
==
그리고.!=
으로 합니다는 개체의 ID를 기반으로 합니다.따라서 동일한 동일성을 가진 인스턴스의 동일성 비교는 동일성으로 귀결되고, 다른 동일성을 가진 인스턴스의 동일성 비교는 불평등으로 귀결됩니다.의 동기는 이어야 한다는 입니다)입니다.x is y
x == y
).()
<
,>
,<=
,그리고.>=
하면 는가 합니다. 시도가 발생합니다.TypeError
. 이러한 기본 동작의 동기는 동등성에 대한 유사한 불변성이 없기 때문입니다.[이것은 와 같이 부정확하고, 와 같이 반사적이며, 와 같이 반사적입니다.]
.object
에서는 Python 문서에서 설명한 대로 모든 하위 클래스에서 상속되는 특수 비교 메서드의 기본 구현을 제공합니다.
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
이른바 '부자 비교' 방식입니다. 관계는 .다
x<y
x.__lt__(y)
,x<=y
x.__le__(y)
,x==y
x.__eq__(y)
,x!=y
x.__ne__(y)
,x>y
x.__gt__(y)
,그리고.x>=y
x.__ge__(y)
.를 할 수 .
NotImplemented
지정된 인수 쌍에 대한 연산을 구현하지 않는 경우.[…]
에는 스왑된 되는 경우 ( 됩니다).
__lt__()
그리고.__gt__()
입니다.__le__()
그리고.__ge__()
이고입니다__eq__()
그리고.__ne__()
그들 자신의 반영입니다.피연산자가 다른 유형이고 오른쪽 피연산자 유형이 왼쪽 피연산자 유형의 직접 또는 간접 하위 클래스인 경우 오른쪽 피연산자의 반사 방식이 우선 순위를 가지며, 그렇지 않으면 왼쪽 피연산자의 방식이 우선 순위를 갖습니다.가상 서브클래싱은 고려되지 않습니다.
R = (R)이므로 비교 xRy는 역비교 yRx(Python 문서에서 비공식적으로 'reflected'로 명명됨)와 같습니다.따라서 비교 연산의 결과를 계산하는 두 가지 방법이 있습니다.x operator y
중 를 호출하는 중 : x.__operator__(y)
아니면y.__operatorT__(x)
과 같은 파이썬은 다음과 같은 컴퓨팅 전략을 사용합니다.
- 은라고 부릅니다.
x.__operator__(y)
피연산자의한라고 .y.__operatorT__(x)
(조상의 역특수비교법을 무시하기 위해 클래스를 allowing합니다.) - 피연산자가.
x
그리고.y
되지 않습니다 값음으로 표시).NotImplemented
), 역 특수 비교법을 1차 폴백이라고 합니다. - 피연산자가.
x
그리고.y
되지 않습니다 값음으로 표시).NotImplemented
), 합니다.TypeError
합니다.==
그리고.!=
와 y을 하고 아이덴티티합니다를비합니다.x
그리고.y
두 번째 폴백(의 반사율 특성을 lever링함)으로==
.!=
). - 결과를 반환합니다.
C python에서 이것은 C 코드로 구현되는데, 이것은 Python 코드로 번역될 수 있습니다 (이름들과 함께).eq
위해서==
,ne
위해서!=
,lt
위해서<
,gt
위해서>
,le
위해서<=
그리고.ge
위해서>=
):
def eq(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__eq__(left)
if result is NotImplemented:
result = left.__eq__(right)
else:
result = left.__eq__(right)
if result is NotImplemented:
result = right.__eq__(left)
if result is NotImplemented:
result = left is right
return result
def ne(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__ne__(left)
if result is NotImplemented:
result = left.__ne__(right)
else:
result = left.__ne__(right)
if result is NotImplemented:
result = right.__ne__(left)
if result is NotImplemented:
result = left is not right
return result
def lt(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__gt__(left)
if result is NotImplemented:
result = left.__lt__(right)
else:
result = left.__lt__(right)
if result is NotImplemented:
result = right.__gt__(left)
if result is NotImplemented:
raise TypeError(
f"'<' not supported between instances of '{type(left).__name__}' "
f"and '{type(right).__name__}'"
)
return result
def gt(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__lt__(left)
if result is NotImplemented:
result = left.__gt__(right)
else:
result = left.__gt__(right)
if result is NotImplemented:
result = right.__lt__(left)
if result is NotImplemented:
raise TypeError(
f"'>' not supported between instances of '{type(left).__name__}' "
f"and '{type(right).__name__}'"
)
return result
def le(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__ge__(left)
if result is NotImplemented:
result = left.__le__(right)
else:
result = left.__le__(right)
if result is NotImplemented:
result = right.__ge__(left)
if result is NotImplemented:
raise TypeError(
f"'<=' not supported between instances of '{type(left).__name__}' "
f"and '{type(right).__name__}'"
)
return result
def ge(left, right):
if type(left) != type(right) and isinstance(right, type(left)):
result = right.__le__(left)
if result is NotImplemented:
result = left.__ge__(right)
else:
result = left.__ge__(right)
if result is NotImplemented:
result = right.__le__(left)
if result is NotImplemented:
raise TypeError(
f"'>=' not supported between instances of '{type(left).__name__}' "
f"and '{type(right).__name__}'"
)
return result
R = ¬(¬R)이므로 비교 xRy는 보 비교 ¬(x ¬Ry)와 같습니다.≠ 는 =의 보완이므로 특별한 방법입니다.__ne__
방법됩니다의 됩니다.__eq__
기본적으로 지원되는 피연산자의 경우, 다른 특별한 비교 방법은 기본적으로 독립적으로 구현됩니다(≤는 <과 =의 결합이고, ≥는 >과 =의 결합이라는 사실은 놀랍게도 고려되지 않습니다). 즉, 현재 특별한 방법은__le__
그리고.__ge__
를 구현해야 합니다). Python 설명서에서 설명한 바와 같이:
으로,
__ne__()
단__eq__()
시킵니다.NotImplemented
에는 다른 를 들어 . 의 입니다. 예를 들어, 다음과 같은 진실이 있습니다.(x<y or x==y)
는 .x<=y
.
CPython에서 이것은 C 코드로 구현되며, Python 코드로 번역할 수 있습니다.
def __eq__(self, other):
return self is other or NotImplemented
def __ne__(self, other):
result = self.__eq__(other)
if result is not NotImplemented:
return not result
return NotImplemented
def __lt__(self, other):
return NotImplemented
def __gt__(self, other):
return NotImplemented
def __le__(self, other):
return NotImplemented
def __ge__(self, other):
return NotImplemented
기본적으로 다음과 같습니다.
-
x operator y
합니다를 .TypeError
합니다.==
그리고.!=
이 합니다 합니다.True
그리고.False
x
그리고.y
이 동일한다를비합니다.False
그리고.True
그렇지 않으면, -
x.__operator__(y)
합니다를(를) 합니다.NotImplemented
__eq__
그리고.__ne__
이 합니다 합니다.True
그리고.False
x
그리고.y
한 값과 값이 다를과합니다.NotImplemented
그렇지않으면.
언급URL : https://stackoverflow.com/questions/4352244/should-ne-be-implemented-as-the-negation-of-eq
'IT' 카테고리의 다른 글
대소문자를 구분하지 않는 PowerShell 교체 (0) | 2023.10.10 |
---|---|
MySQL에서 LIMIT 1 사용 (0) | 2023.10.10 |
c++ 주 기능에서 다른 기능으로 변경하려면 어떻게 해야 합니까? (0) | 2023.10.10 |
MariaDB 필드의 성배에 값이 있지만 null을 가져왔습니다. (0) | 2023.10.05 |
WP OEM 스크립트를 _content 외부에서 사용하는 방법 (0) | 2023.10.05 |