`if None .__ eq __ (“a”)`가 True로 평가되는 이유는 무엇입니까?


146

파이썬 3.7에서 다음 문장을 실행하면 (내 테스트에서) 인쇄됩니다 b.

if None.__eq__("a"):
    print("b")

그러나로 None.__eq__("a")평가됩니다 NotImplemented.

당연히로 "a".__eq__("a")평가 True하고로 "b".__eq__("a")평가합니다 False.

처음에는 함수의 반환 값을 테스트 할 때 이것을 발견했지만 두 번째 경우에는 아무것도 반환하지 않았으므로 함수가 반환되었습니다 None.

무슨 일이야?

답변:


178

이것은 __dunder__메소드가 동등한 연산자를 대체하기에 적절하지 않은 경우가 많으므로 직접 사용해서는 안되는 이유에 대한 훌륭한 예입니다 . 당신은 사용해야 ==평등 비교 대신 연산자를, 또는이 특별한 경우에 검사 할 때 None사용 is(자세한 내용은 답변 아래로 이동).

너는 해냈어

None.__eq__('a')
# NotImplemented

NotImplemented비교되는 유형이 다르기 때문에 어느 것이 반환 됩니다. 유형이 다른 두 객체가 이러한 방식으로 비교되는 또 다른 예를 고려하십시오 (예 : 1및) 'a'. 수행하는 (1).__eq__('a')것도 올바르지 않으며을 반환 NotImplemented합니다. 이 두 값을 동등하게 비교하는 올바른 방법은

1 == 'a'
# False

여기서 일어나는 일은

  1. 첫째 (1).__eq__('a'), 어떤 반환을 시도합니다 NotImplemented. 이는 작업이 지원되지 않음을 나타냅니다.
  2. 'a'.__eq__(1)가 호출되어 동일한을 반환합니다 NotImplemented. 그래서,
  3. 객체는 동일하지 않은 것으로 취급되어 False반환됩니다.

이 방법을 설명하기 위해 일부 사용자 정의 클래스를 사용하는 멋진 MCVE가 있습니다.

class A:
    def __eq__(self, other):
        print('A.__eq__')
        return NotImplemented

class B:
    def __eq__(self, other):
        print('B.__eq__')
        return NotImplemented

class C:
    def __eq__(self, other):
        print('C.__eq__')
        return True

a = A()
b = B()
c = C()

print(a == b)
# A.__eq__
# B.__eq__
# False

print(a == c)
# A.__eq__
# C.__eq__
# True

print(c == a)
# C.__eq__
# True

물론, 작업이 true를 반환 하는지 는 설명하지 않습니다 . 이것은 NotImplemented실제로 진실한 가치 이기 때문 입니다.

bool(None.__eq__("a"))
# True

같은

bool(NotImplemented)
# True

어떤 값이 진실되고 허위로 간주되는지에 대한 자세한 내용 은 이 답변 뿐만 아니라 진실 값 테스트 에 대한 문서 섹션을 참조하십시오 . 그것은 여기에 주목할 필요가있다 truthy이지만, 그것은 다른 이야기가 클래스가 정의했다이었을 것 또는 반환 된 방법 또는 각각을.NotImplemented__bool____len__False0


==연산자 와 동등한 기능을 원하면 다음을 사용하십시오 operator.eq.

import operator
operator.eq(1, 'a')
# False

그러나 앞에서 언급했듯이이 특정 시나리오 에서는 확인하려는 다음을 None사용하십시오 is.

var = 'a'
var is None
# False

var2 = None
var2 is None
# True

이것과 동등한 기능을 사용하고 있습니다 operator.is_:

operator.is_(var2, None)
# True

None는 특별한 객체이며, 어떤 시점에서도 메모리에 1 개의 버전 만 존재합니다. IOW는 NoneType클래스 의 유일한 싱글 톤입니다 (그러나 동일한 객체는 여러 참조를 가질 수 있습니다). PEP8 가이드 라인 이 명시합니다

싱글 톤과의 비교 None는 항상 등호 연산자를 사용하지 않고 is또는 로 수행해야합니다 is not.

요약하면, 싱글이 좋아하는 위해 None를 가진 참조 검사가 is더 적합, 모두 비록 ==is잘 작동합니다.


33

당신이보고있는 결과는

None.__eq__("a") # evaluates to NotImplemented

로 평가되고 NotImplemented, NotImplemented진실의 가치는 다음과 같이 문서화됩니다 True:

https://docs.python.org/3/library/constants.html

(예를 들면 진 특별한 방법에 의해 반환되는 특수한 값 __eq__(), __lt__(), __add__(), __rsub__(), 등)의 동작은 다른 유형에 대하여 구현되지 않는다는 것을 표시하는 단계; 인플레 이스 (in-place) 진 특별한 방법 (예에 의해 반환 될 수 있습니다 __imul__(), __iand__()같은 목적 등). 진실의 가치는 사실입니다.

__eq()__사용하지 않고 수동으로 메소드 를 호출하는 경우 ==, 리턴 될 가능성 NotImplemented과 실제 값이 참인지 를 처리 할 준비가되어 있어야 합니다.


16

당신은 이미 생각으로 None.__eq__("a")평가를 NotImplemented하지만 당신은 뭔가를 시도하는 경우

if NotImplemented:
    print("Yes")
else:
    print("No")

결과는

이것은 진실의 가치가 NotImplemented true

따라서 질문의 결과는 분명합니다.

None.__eq__(something) 수확량 NotImplemented

그리고 bool(NotImplemented)참으로 평가

그래서 if None.__eq__("a")항상 True입니다


1

왜?

예를 반환합니다 NotImplemented.

>>> None.__eq__('a')
NotImplemented
>>> 

그러나 이것을 보면 :

>>> bool(NotImplemented)
True
>>> 

NotImplementedtruthy 값이 실제로는 반환 이유의 때문에 b, 아무것도 True이다 통과 할 것이다, 아무것도 False하지 않을 것입니다.

그것을 해결하는 방법?

당신이 그것이 있는지 확인해야 True하므로 더 의심스러워하십시오.

>>> NotImplemented == True
False
>>> 

그래서 당신은 할 것입니다 :

>>> if None.__eq__('a') == True:
    print('b')


>>> 

보시다시피 아무것도 반환하지 않습니다.


1
가장 시각적으로 명확한 답변-가치있는 추가-감사합니다
scharfmn

1
:) "가중 추가"는 내가 말하려는 내용을 정확히 포착하지 못합니다. (아무도 잘 아시겠지만) 아마도 "늦은 것의 우수성"은 제가 원했던 것입니다-건배
scharfmn

@scharfmn 그래? 이 답변이 이전에 다루지 않은 추가 사항에 대해 어떻게 생각하는지 알고 싶습니다.
cs95

어쨌든 여기에 시각적 /
재현적인

@scharfmn ... 프롬프트가 제거되었지만 허용 된 답변도 있습니다. 터미널 프롬프트가 느리게 남아 있기 때문에 전적으로 투표 했습니까?
cs95
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.