Why does calling Python's 'magic method' not do type conversion like it would for the corresponding operator?
When I subtract a float from an integer (e.g. 1-2.0
), Python does implicit type conversion (I think). But when I call what I thought was the same operation using the magic method __sub__
, it suddenly does not anymore.
What am I missing here? When I overload operators for my own classes, is there a way around this other than explicitly casting input to whatever type I need?
a=1
a.__sub__(2.)
# returns NotImplemented
a.__rsub__(2.)
# returns NotImplemented
# yet, of course:
a-2.
# returns -1.0
python casting
add a comment |
When I subtract a float from an integer (e.g. 1-2.0
), Python does implicit type conversion (I think). But when I call what I thought was the same operation using the magic method __sub__
, it suddenly does not anymore.
What am I missing here? When I overload operators for my own classes, is there a way around this other than explicitly casting input to whatever type I need?
a=1
a.__sub__(2.)
# returns NotImplemented
a.__rsub__(2.)
# returns NotImplemented
# yet, of course:
a-2.
# returns -1.0
python casting
add a comment |
When I subtract a float from an integer (e.g. 1-2.0
), Python does implicit type conversion (I think). But when I call what I thought was the same operation using the magic method __sub__
, it suddenly does not anymore.
What am I missing here? When I overload operators for my own classes, is there a way around this other than explicitly casting input to whatever type I need?
a=1
a.__sub__(2.)
# returns NotImplemented
a.__rsub__(2.)
# returns NotImplemented
# yet, of course:
a-2.
# returns -1.0
python casting
When I subtract a float from an integer (e.g. 1-2.0
), Python does implicit type conversion (I think). But when I call what I thought was the same operation using the magic method __sub__
, it suddenly does not anymore.
What am I missing here? When I overload operators for my own classes, is there a way around this other than explicitly casting input to whatever type I need?
a=1
a.__sub__(2.)
# returns NotImplemented
a.__rsub__(2.)
# returns NotImplemented
# yet, of course:
a-2.
# returns -1.0
python casting
python casting
asked 5 hours ago
dopplerdoppler
1467
1467
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
a - b
isn't just a.__sub__(b)
. It also tries b.__rsub__(a)
if a
can't handle the operation, and in the 1 - 2.
case, it's the float's __rsub__
that handles the operation.
>>> (2.).__rsub__(1)
-1.0
You ran a.__rsub__(2.)
, but that's the wrong __rsub__
. You need the right-side operand's __rsub__
, not the left-side operand.
There is no implicit type conversion built into the subtraction operator. float.__rsub__
has to handle ints manually. If you want type conversion in your own operator implementations, you'll have to handle that manually too.
6
It's worth noting that theNotImplemented
result that is returned by the calls in the question are the signal to try the reverse method.
– Blckknght
5 hours ago
Thanks! I was aware it would try__rsub__
but didn't know it would reverse the argument order.
– doppler
5 hours ago
2
@doppler: It'd be pretty pointless to have the left operand handle both__sub__
and__rsub__
. That'd just be two methods with the exact same job, and the right operand would have no opportunity to supply an implementation.
– user2357112
4 hours ago
@user2357112 soself.__rsub__(other)
really just callsother.__sub__(self)
, if that makes any sense?
– doppler
4 hours ago
2
@doppler: No.self.__rsub__(other)
is called forother - self
ifother
can't handle it. Callingother.__sub__(self)
would be pointless. We already knowother
can't handle it.
– user2357112
4 hours ago
|
show 1 more comment
@user2357112 already said it well but nothing like an example.
class A:
def __sub__(self, other):
print('A.__sub__')
if not isinstance(other, A):
return NotImplemented
return 0
def __rsub__(self, other):
print('A.__rsub__')
if not isinstance(other, A):
return NotImplemented
return 0
class B:
def __sub__(self, other):
print('B.__sub__')
if not isinstance(other, B):
return NotImplemented
return 0
a1 = A()
a2 = A()
b = B()
a1 - a2
A.__sub__
# 0
Objects a1
and a2
are compatible (both type A
), a valid result is returned.
Next, consider,
b - a1
B.__sub__
A.__rsub__
# TypeError: unsupported operand type(s) for -: 'B' and 'A'
Objects b
and a1
are not compatible. First, b.__sub__
is tried, which returns NotImplemented
, so a1.__rsub__
is tried, which also returns NotImplemented
. So a TypeError
is raised.
Finally,
a1 - b
A.__sub__
# TypeError: unsupported operand type(s) for -: 'A' and 'B'
This time, a1.__sub__
is tried first, which returns NotImplemented
. Now, since b.__rsub__
is not defined, so a TypeError
is raised.
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%2f54775946%2fwhy-does-calling-pythons-magic-method-not-do-type-conversion-like-it-would-fo%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
a - b
isn't just a.__sub__(b)
. It also tries b.__rsub__(a)
if a
can't handle the operation, and in the 1 - 2.
case, it's the float's __rsub__
that handles the operation.
>>> (2.).__rsub__(1)
-1.0
You ran a.__rsub__(2.)
, but that's the wrong __rsub__
. You need the right-side operand's __rsub__
, not the left-side operand.
There is no implicit type conversion built into the subtraction operator. float.__rsub__
has to handle ints manually. If you want type conversion in your own operator implementations, you'll have to handle that manually too.
6
It's worth noting that theNotImplemented
result that is returned by the calls in the question are the signal to try the reverse method.
– Blckknght
5 hours ago
Thanks! I was aware it would try__rsub__
but didn't know it would reverse the argument order.
– doppler
5 hours ago
2
@doppler: It'd be pretty pointless to have the left operand handle both__sub__
and__rsub__
. That'd just be two methods with the exact same job, and the right operand would have no opportunity to supply an implementation.
– user2357112
4 hours ago
@user2357112 soself.__rsub__(other)
really just callsother.__sub__(self)
, if that makes any sense?
– doppler
4 hours ago
2
@doppler: No.self.__rsub__(other)
is called forother - self
ifother
can't handle it. Callingother.__sub__(self)
would be pointless. We already knowother
can't handle it.
– user2357112
4 hours ago
|
show 1 more comment
a - b
isn't just a.__sub__(b)
. It also tries b.__rsub__(a)
if a
can't handle the operation, and in the 1 - 2.
case, it's the float's __rsub__
that handles the operation.
>>> (2.).__rsub__(1)
-1.0
You ran a.__rsub__(2.)
, but that's the wrong __rsub__
. You need the right-side operand's __rsub__
, not the left-side operand.
There is no implicit type conversion built into the subtraction operator. float.__rsub__
has to handle ints manually. If you want type conversion in your own operator implementations, you'll have to handle that manually too.
6
It's worth noting that theNotImplemented
result that is returned by the calls in the question are the signal to try the reverse method.
– Blckknght
5 hours ago
Thanks! I was aware it would try__rsub__
but didn't know it would reverse the argument order.
– doppler
5 hours ago
2
@doppler: It'd be pretty pointless to have the left operand handle both__sub__
and__rsub__
. That'd just be two methods with the exact same job, and the right operand would have no opportunity to supply an implementation.
– user2357112
4 hours ago
@user2357112 soself.__rsub__(other)
really just callsother.__sub__(self)
, if that makes any sense?
– doppler
4 hours ago
2
@doppler: No.self.__rsub__(other)
is called forother - self
ifother
can't handle it. Callingother.__sub__(self)
would be pointless. We already knowother
can't handle it.
– user2357112
4 hours ago
|
show 1 more comment
a - b
isn't just a.__sub__(b)
. It also tries b.__rsub__(a)
if a
can't handle the operation, and in the 1 - 2.
case, it's the float's __rsub__
that handles the operation.
>>> (2.).__rsub__(1)
-1.0
You ran a.__rsub__(2.)
, but that's the wrong __rsub__
. You need the right-side operand's __rsub__
, not the left-side operand.
There is no implicit type conversion built into the subtraction operator. float.__rsub__
has to handle ints manually. If you want type conversion in your own operator implementations, you'll have to handle that manually too.
a - b
isn't just a.__sub__(b)
. It also tries b.__rsub__(a)
if a
can't handle the operation, and in the 1 - 2.
case, it's the float's __rsub__
that handles the operation.
>>> (2.).__rsub__(1)
-1.0
You ran a.__rsub__(2.)
, but that's the wrong __rsub__
. You need the right-side operand's __rsub__
, not the left-side operand.
There is no implicit type conversion built into the subtraction operator. float.__rsub__
has to handle ints manually. If you want type conversion in your own operator implementations, you'll have to handle that manually too.
edited 5 hours ago
answered 5 hours ago
user2357112user2357112
155k12163258
155k12163258
6
It's worth noting that theNotImplemented
result that is returned by the calls in the question are the signal to try the reverse method.
– Blckknght
5 hours ago
Thanks! I was aware it would try__rsub__
but didn't know it would reverse the argument order.
– doppler
5 hours ago
2
@doppler: It'd be pretty pointless to have the left operand handle both__sub__
and__rsub__
. That'd just be two methods with the exact same job, and the right operand would have no opportunity to supply an implementation.
– user2357112
4 hours ago
@user2357112 soself.__rsub__(other)
really just callsother.__sub__(self)
, if that makes any sense?
– doppler
4 hours ago
2
@doppler: No.self.__rsub__(other)
is called forother - self
ifother
can't handle it. Callingother.__sub__(self)
would be pointless. We already knowother
can't handle it.
– user2357112
4 hours ago
|
show 1 more comment
6
It's worth noting that theNotImplemented
result that is returned by the calls in the question are the signal to try the reverse method.
– Blckknght
5 hours ago
Thanks! I was aware it would try__rsub__
but didn't know it would reverse the argument order.
– doppler
5 hours ago
2
@doppler: It'd be pretty pointless to have the left operand handle both__sub__
and__rsub__
. That'd just be two methods with the exact same job, and the right operand would have no opportunity to supply an implementation.
– user2357112
4 hours ago
@user2357112 soself.__rsub__(other)
really just callsother.__sub__(self)
, if that makes any sense?
– doppler
4 hours ago
2
@doppler: No.self.__rsub__(other)
is called forother - self
ifother
can't handle it. Callingother.__sub__(self)
would be pointless. We already knowother
can't handle it.
– user2357112
4 hours ago
6
6
It's worth noting that the
NotImplemented
result that is returned by the calls in the question are the signal to try the reverse method.– Blckknght
5 hours ago
It's worth noting that the
NotImplemented
result that is returned by the calls in the question are the signal to try the reverse method.– Blckknght
5 hours ago
Thanks! I was aware it would try
__rsub__
but didn't know it would reverse the argument order.– doppler
5 hours ago
Thanks! I was aware it would try
__rsub__
but didn't know it would reverse the argument order.– doppler
5 hours ago
2
2
@doppler: It'd be pretty pointless to have the left operand handle both
__sub__
and __rsub__
. That'd just be two methods with the exact same job, and the right operand would have no opportunity to supply an implementation.– user2357112
4 hours ago
@doppler: It'd be pretty pointless to have the left operand handle both
__sub__
and __rsub__
. That'd just be two methods with the exact same job, and the right operand would have no opportunity to supply an implementation.– user2357112
4 hours ago
@user2357112 so
self.__rsub__(other)
really just calls other.__sub__(self)
, if that makes any sense?– doppler
4 hours ago
@user2357112 so
self.__rsub__(other)
really just calls other.__sub__(self)
, if that makes any sense?– doppler
4 hours ago
2
2
@doppler: No.
self.__rsub__(other)
is called for other - self
if other
can't handle it. Calling other.__sub__(self)
would be pointless. We already know other
can't handle it.– user2357112
4 hours ago
@doppler: No.
self.__rsub__(other)
is called for other - self
if other
can't handle it. Calling other.__sub__(self)
would be pointless. We already know other
can't handle it.– user2357112
4 hours ago
|
show 1 more comment
@user2357112 already said it well but nothing like an example.
class A:
def __sub__(self, other):
print('A.__sub__')
if not isinstance(other, A):
return NotImplemented
return 0
def __rsub__(self, other):
print('A.__rsub__')
if not isinstance(other, A):
return NotImplemented
return 0
class B:
def __sub__(self, other):
print('B.__sub__')
if not isinstance(other, B):
return NotImplemented
return 0
a1 = A()
a2 = A()
b = B()
a1 - a2
A.__sub__
# 0
Objects a1
and a2
are compatible (both type A
), a valid result is returned.
Next, consider,
b - a1
B.__sub__
A.__rsub__
# TypeError: unsupported operand type(s) for -: 'B' and 'A'
Objects b
and a1
are not compatible. First, b.__sub__
is tried, which returns NotImplemented
, so a1.__rsub__
is tried, which also returns NotImplemented
. So a TypeError
is raised.
Finally,
a1 - b
A.__sub__
# TypeError: unsupported operand type(s) for -: 'A' and 'B'
This time, a1.__sub__
is tried first, which returns NotImplemented
. Now, since b.__rsub__
is not defined, so a TypeError
is raised.
add a comment |
@user2357112 already said it well but nothing like an example.
class A:
def __sub__(self, other):
print('A.__sub__')
if not isinstance(other, A):
return NotImplemented
return 0
def __rsub__(self, other):
print('A.__rsub__')
if not isinstance(other, A):
return NotImplemented
return 0
class B:
def __sub__(self, other):
print('B.__sub__')
if not isinstance(other, B):
return NotImplemented
return 0
a1 = A()
a2 = A()
b = B()
a1 - a2
A.__sub__
# 0
Objects a1
and a2
are compatible (both type A
), a valid result is returned.
Next, consider,
b - a1
B.__sub__
A.__rsub__
# TypeError: unsupported operand type(s) for -: 'B' and 'A'
Objects b
and a1
are not compatible. First, b.__sub__
is tried, which returns NotImplemented
, so a1.__rsub__
is tried, which also returns NotImplemented
. So a TypeError
is raised.
Finally,
a1 - b
A.__sub__
# TypeError: unsupported operand type(s) for -: 'A' and 'B'
This time, a1.__sub__
is tried first, which returns NotImplemented
. Now, since b.__rsub__
is not defined, so a TypeError
is raised.
add a comment |
@user2357112 already said it well but nothing like an example.
class A:
def __sub__(self, other):
print('A.__sub__')
if not isinstance(other, A):
return NotImplemented
return 0
def __rsub__(self, other):
print('A.__rsub__')
if not isinstance(other, A):
return NotImplemented
return 0
class B:
def __sub__(self, other):
print('B.__sub__')
if not isinstance(other, B):
return NotImplemented
return 0
a1 = A()
a2 = A()
b = B()
a1 - a2
A.__sub__
# 0
Objects a1
and a2
are compatible (both type A
), a valid result is returned.
Next, consider,
b - a1
B.__sub__
A.__rsub__
# TypeError: unsupported operand type(s) for -: 'B' and 'A'
Objects b
and a1
are not compatible. First, b.__sub__
is tried, which returns NotImplemented
, so a1.__rsub__
is tried, which also returns NotImplemented
. So a TypeError
is raised.
Finally,
a1 - b
A.__sub__
# TypeError: unsupported operand type(s) for -: 'A' and 'B'
This time, a1.__sub__
is tried first, which returns NotImplemented
. Now, since b.__rsub__
is not defined, so a TypeError
is raised.
@user2357112 already said it well but nothing like an example.
class A:
def __sub__(self, other):
print('A.__sub__')
if not isinstance(other, A):
return NotImplemented
return 0
def __rsub__(self, other):
print('A.__rsub__')
if not isinstance(other, A):
return NotImplemented
return 0
class B:
def __sub__(self, other):
print('B.__sub__')
if not isinstance(other, B):
return NotImplemented
return 0
a1 = A()
a2 = A()
b = B()
a1 - a2
A.__sub__
# 0
Objects a1
and a2
are compatible (both type A
), a valid result is returned.
Next, consider,
b - a1
B.__sub__
A.__rsub__
# TypeError: unsupported operand type(s) for -: 'B' and 'A'
Objects b
and a1
are not compatible. First, b.__sub__
is tried, which returns NotImplemented
, so a1.__rsub__
is tried, which also returns NotImplemented
. So a TypeError
is raised.
Finally,
a1 - b
A.__sub__
# TypeError: unsupported operand type(s) for -: 'A' and 'B'
This time, a1.__sub__
is tried first, which returns NotImplemented
. Now, since b.__rsub__
is not defined, so a TypeError
is raised.
answered 38 mins ago
coldspeedcoldspeed
132k23139223
132k23139223
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.
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%2f54775946%2fwhy-does-calling-pythons-magic-method-not-do-type-conversion-like-it-would-fo%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