`if None .__ eq __ (“a”)`가 True로 평가되는 이유는 무엇입니까?
파이썬 3.7에서 다음 문장을 실행하면 (내 테스트에서) 인쇄됩니다 b
.
if None.__eq__("a"):
print("b")
그러나로 None.__eq__("a")
평가됩니다 NotImplemented
.
당연히로 "a".__eq__("a")
평가 True
하고로 "b".__eq__("a")
평가합니다 False
.
처음에는 함수의 반환 값을 테스트 할 때 이것을 발견했지만 두 번째 경우에는 아무것도 반환하지 않았으므로 함수가 반환되었습니다 None
.
무슨 일이야?
이것은 __dunder__
메소드가 동등한 연산자를 대체하기에 적합하지 않은 경우가 많으므로 직접 사용해서는 안되는 이유에 대한 훌륭한 예입니다 . 당신은 사용해야 ==
평등 비교 대신 연산자를, 또는이 특별한 경우에 검사 할 때 None
사용 is
(자세한 내용은 답변 아래로 이동).
너는 해냈어
None.__eq__('a')
# NotImplemented
NotImplemented
비교되는 유형이 다르기 때문에 어느 것이 반환 됩니다. 유형이 다른 두 객체가 이러한 방식으로 비교되는 또 다른 예를 고려하십시오 (예 : 1
및) 'a'
. 수행하는 (1).__eq__('a')
것도 올바르지 않으며을 반환 NotImplemented
합니다. 이 두 값을 동등하게 비교하는 올바른 방법은
1 == 'a'
# False
여기서 일어나는 일은
- 첫째
(1).__eq__('a')
, 어떤 반환을 시도합니다NotImplemented
. 이는 작업이 지원되지 않음을 나타냅니다. 'a'.__eq__(1)
가 호출되어 동일한을 반환합니다NotImplemented
. 그래서,- 객체는 동일하지 않은 것으로 취급되어
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
For more information on what values are considered truthy and falsy, see the docs section on Truth Value Testing, as well as this answer. It is worth noting here that NotImplemented
is truthy, but it would have been a different story had the class defined a __bool__
or __len__
method that returned False
or 0
respectively.
If you want the functional equivalent of the ==
operator, use operator.eq
:
import operator
operator.eq(1, 'a')
# False
However, as mentioned earlier, for this specific scenario, where you are checking for None
, use is
:
var = 'a'
var is None
# False
var2 = None
var2 is None
# True
The functional equivalent of this is using operator.is_
:
operator.is_(var2, None)
# True
None
is a special object, and only 1 version exists in memory at any point of time. IOW, it is the sole singleton of the NoneType
class (but the same object may have any number of references). The PEP8 guidelines make this explicit:
Comparisons to singletons like
None
should always be done withis
oris not
, never the equality operators.
In summary, for singletons like None
, a reference check with is
is more appropriate, although both ==
and is
will work just fine.
The result you are seeing is caused by that fact that
None.__eq__("a") # evaluates to NotImplemented
evaluates to NotImplemented
, and NotImplemented
's truth value is documented to be True
:
https://docs.python.org/3/library/constants.html
Special value which should be returned by the binary special methods (e.g.
__eq__()
,__lt__()
,__add__()
,__rsub__()
, etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g.__imul__()
,__iand__()
, etc.) for the same purpose. Its truth value is true.
If you call the __eq()__
method manually rather than just using ==
, you need to be prepared to deal with the possibility it may return NotImplemented
and that its truth value is true.
As you already figured None.__eq__("a")
evaluates to NotImplemented
however if you try something like
if NotImplemented:
print("Yes")
else:
print("No")
the result is
yes
this mean that the truth value of NotImplemented
true
Therefor the outcome of the question is obvious:
None.__eq__(something)
yields NotImplemented
And bool(NotImplemented)
evaluates to True
So if None.__eq__("a")
is always True
Why?
It returns a NotImplemented
, yeah:
>>> None.__eq__('a')
NotImplemented
>>>
But if you look at this:
>>> bool(NotImplemented)
True
>>>
NotImplemented
is actually a truthy value, so that's why it returns b
, anything that is True
will pass, anything that is False
wouldn't.
How to solve it?
You have to check if it is True
, so be more suspicious, as you see:
>>> NotImplemented == True
False
>>>
So you would do:
>>> if None.__eq__('a') == True:
print('b')
>>>
And as you see, it wouldn't return anything.
'development' 카테고리의 다른 글
여러 파일로 views.py 분할 (0) | 2020.06.17 |
---|---|
arr = []가 arr = new Array보다 빠른 이유는 무엇입니까? (0) | 2020.06.17 |
OS 커널이란 무엇입니까? (0) | 2020.06.17 |
asp.net MVC3의 사용자 정의 오류 페이지 (0) | 2020.06.17 |
파이썬에서 두 목록이 원형으로 동일한 지 확인하는 방법 (0) | 2020.06.17 |