development

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

big-blog 2020. 6. 17. 07:41
반응형

`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. 첫째 (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

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 with is or is 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.

참고URL : https://stackoverflow.com/questions/53984116/why-does-if-none-eq-a-seem-to-evaluate-to-true-but-not-quite

반응형