Why does `if None.__eq__(“a”)` evaluate to True?
If you execute the following statement in Python 3.7, it will (from my testing) print b
:
if None.__eq__("a"):
print("b")
However, None.__eq__("a")
evaluates to NotImplemented
.
Naturally, "a".__eq__("a")
evaluates to True
, and "b".__eq__("a")
evaluates to False
.
I initially discovered this when testing the return value of a function, but didn't return anything in the second case -- so, the function returned None
.
What's going on here?
python python-3.x string equivalence
add a comment |
If you execute the following statement in Python 3.7, it will (from my testing) print b
:
if None.__eq__("a"):
print("b")
However, None.__eq__("a")
evaluates to NotImplemented
.
Naturally, "a".__eq__("a")
evaluates to True
, and "b".__eq__("a")
evaluates to False
.
I initially discovered this when testing the return value of a function, but didn't return anything in the second case -- so, the function returned None
.
What's going on here?
python python-3.x string equivalence
add a comment |
If you execute the following statement in Python 3.7, it will (from my testing) print b
:
if None.__eq__("a"):
print("b")
However, None.__eq__("a")
evaluates to NotImplemented
.
Naturally, "a".__eq__("a")
evaluates to True
, and "b".__eq__("a")
evaluates to False
.
I initially discovered this when testing the return value of a function, but didn't return anything in the second case -- so, the function returned None
.
What's going on here?
python python-3.x string equivalence
If you execute the following statement in Python 3.7, it will (from my testing) print b
:
if None.__eq__("a"):
print("b")
However, None.__eq__("a")
evaluates to NotImplemented
.
Naturally, "a".__eq__("a")
evaluates to True
, and "b".__eq__("a")
evaluates to False
.
I initially discovered this when testing the return value of a function, but didn't return anything in the second case -- so, the function returned None
.
What's going on here?
python python-3.x string equivalence
python python-3.x string equivalence
edited 4 hours ago
coldspeed
120k19116194
120k19116194
asked 5 hours ago
The AI Architect
1111312
1111312
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
This is a great example of why the __dunder__
methods should not be used directly as they are quite often not appropriate replacements for their equivalent operators; in this case you should use the ==
operator instead. You've done
None.__eq__('a')
# NotImplemented
Which returns NotImplemented
since the types being compared are different. Try comparing any two objects with different types like this (ex (1).__eq__('a')
). The right way to do this would be
None == 'a'
# False
What happens here is
- First,
None.__eq__('a')
is tried, which returnsNotImplemented
. This indicates that the operation is not supported, so
'a'.__eq__(None)
is called, which also returns the sameNotImplemented
. So,- The objects are treated as if they are not the same, and
False
is returned.
Here's a nice little MCVE to illustrate how this happens:
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
Of course, that doesn't explain why the operation returns true. This is because NotImplemented
is actually a truthy value:
bool(None.__eq__("a"))
# True
Same as,
bool(NotImplemented)
# True
For more information on what values are considered truthy and falsey, see the docs section on Truth Value Testing, as well as this answer.
If you want the functional equivalent of the ==
operator, use operator.eq
:
import operator
operator.eq(None, 'a')
# False
add a comment |
The result you are seeing is documented
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 you need to be prepared to deal with the possibility it may return NotImplemented
and that its truth value is true.
add a comment |
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 NotImplemented.__bool__()
returns 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
New contributor
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53984116%2fwhy-does-if-none-eq-a-evaluate-to-true%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
This is a great example of why the __dunder__
methods should not be used directly as they are quite often not appropriate replacements for their equivalent operators; in this case you should use the ==
operator instead. You've done
None.__eq__('a')
# NotImplemented
Which returns NotImplemented
since the types being compared are different. Try comparing any two objects with different types like this (ex (1).__eq__('a')
). The right way to do this would be
None == 'a'
# False
What happens here is
- First,
None.__eq__('a')
is tried, which returnsNotImplemented
. This indicates that the operation is not supported, so
'a'.__eq__(None)
is called, which also returns the sameNotImplemented
. So,- The objects are treated as if they are not the same, and
False
is returned.
Here's a nice little MCVE to illustrate how this happens:
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
Of course, that doesn't explain why the operation returns true. This is because NotImplemented
is actually a truthy value:
bool(None.__eq__("a"))
# True
Same as,
bool(NotImplemented)
# True
For more information on what values are considered truthy and falsey, see the docs section on Truth Value Testing, as well as this answer.
If you want the functional equivalent of the ==
operator, use operator.eq
:
import operator
operator.eq(None, 'a')
# False
add a comment |
This is a great example of why the __dunder__
methods should not be used directly as they are quite often not appropriate replacements for their equivalent operators; in this case you should use the ==
operator instead. You've done
None.__eq__('a')
# NotImplemented
Which returns NotImplemented
since the types being compared are different. Try comparing any two objects with different types like this (ex (1).__eq__('a')
). The right way to do this would be
None == 'a'
# False
What happens here is
- First,
None.__eq__('a')
is tried, which returnsNotImplemented
. This indicates that the operation is not supported, so
'a'.__eq__(None)
is called, which also returns the sameNotImplemented
. So,- The objects are treated as if they are not the same, and
False
is returned.
Here's a nice little MCVE to illustrate how this happens:
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
Of course, that doesn't explain why the operation returns true. This is because NotImplemented
is actually a truthy value:
bool(None.__eq__("a"))
# True
Same as,
bool(NotImplemented)
# True
For more information on what values are considered truthy and falsey, see the docs section on Truth Value Testing, as well as this answer.
If you want the functional equivalent of the ==
operator, use operator.eq
:
import operator
operator.eq(None, 'a')
# False
add a comment |
This is a great example of why the __dunder__
methods should not be used directly as they are quite often not appropriate replacements for their equivalent operators; in this case you should use the ==
operator instead. You've done
None.__eq__('a')
# NotImplemented
Which returns NotImplemented
since the types being compared are different. Try comparing any two objects with different types like this (ex (1).__eq__('a')
). The right way to do this would be
None == 'a'
# False
What happens here is
- First,
None.__eq__('a')
is tried, which returnsNotImplemented
. This indicates that the operation is not supported, so
'a'.__eq__(None)
is called, which also returns the sameNotImplemented
. So,- The objects are treated as if they are not the same, and
False
is returned.
Here's a nice little MCVE to illustrate how this happens:
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
Of course, that doesn't explain why the operation returns true. This is because NotImplemented
is actually a truthy value:
bool(None.__eq__("a"))
# True
Same as,
bool(NotImplemented)
# True
For more information on what values are considered truthy and falsey, see the docs section on Truth Value Testing, as well as this answer.
If you want the functional equivalent of the ==
operator, use operator.eq
:
import operator
operator.eq(None, 'a')
# False
This is a great example of why the __dunder__
methods should not be used directly as they are quite often not appropriate replacements for their equivalent operators; in this case you should use the ==
operator instead. You've done
None.__eq__('a')
# NotImplemented
Which returns NotImplemented
since the types being compared are different. Try comparing any two objects with different types like this (ex (1).__eq__('a')
). The right way to do this would be
None == 'a'
# False
What happens here is
- First,
None.__eq__('a')
is tried, which returnsNotImplemented
. This indicates that the operation is not supported, so
'a'.__eq__(None)
is called, which also returns the sameNotImplemented
. So,- The objects are treated as if they are not the same, and
False
is returned.
Here's a nice little MCVE to illustrate how this happens:
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
Of course, that doesn't explain why the operation returns true. This is because NotImplemented
is actually a truthy value:
bool(None.__eq__("a"))
# True
Same as,
bool(NotImplemented)
# True
For more information on what values are considered truthy and falsey, see the docs section on Truth Value Testing, as well as this answer.
If you want the functional equivalent of the ==
operator, use operator.eq
:
import operator
operator.eq(None, 'a')
# False
edited 40 mins ago
answered 5 hours ago
coldspeed
120k19116194
120k19116194
add a comment |
add a comment |
The result you are seeing is documented
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 you need to be prepared to deal with the possibility it may return NotImplemented
and that its truth value is true.
add a comment |
The result you are seeing is documented
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 you need to be prepared to deal with the possibility it may return NotImplemented
and that its truth value is true.
add a comment |
The result you are seeing is documented
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 you need to be prepared to deal with the possibility it may return NotImplemented
and that its truth value is true.
The result you are seeing is documented
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 you need to be prepared to deal with the possibility it may return NotImplemented
and that its truth value is true.
answered 5 hours ago
Mark Meyer
35.7k32956
35.7k32956
add a comment |
add a comment |
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 NotImplemented.__bool__()
returns 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
New contributor
add a comment |
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 NotImplemented.__bool__()
returns 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
New contributor
add a comment |
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 NotImplemented.__bool__()
returns 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
New contributor
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 NotImplemented.__bool__()
returns 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
New contributor
New contributor
answered 4 hours ago
Kanjiu
1837
1837
New contributor
New contributor
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53984116%2fwhy-does-if-none-eq-a-evaluate-to-true%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown