Why Do 5 + "5" and "5" + 5 Give Different Errors in Python? • Do You Know The Whole Story?
If __radd__() is not part of your answer, read on…
5 + "5"
and"5" + 5
give a different error message because the first calls theint
class's__add__()
dunder method whereas the second calls thestr
class's__add__()
method
…is not a sufficient answer.
I’ve often given this explanation when teaching. And it’s not wrong. I’ll still use it in introductory courses.
But a serendipitous exploration led me down a different route recently…
Why __add__()
Alone Doesn't Fully Explain This
Let's start by looking at the error messages for the two versions:
In the first example, the integer 5
comes first, before the +
operator. The string "5"
is after the +
. This raises a TypeError
, which tells you the types you used with the +
operator are unsupported.
You can't add the string "5"
to the integer 5
. This probably makes sense.
In the second example, the order of the data types is swapped. The string "5"
is before the +
operator and the integer 5
after. You still get a TypeError
, but the message is different. This error message is specific about concatenation of strings. You can only add a string to another string.
First attempt
The +
operator calls the __add__()
special method of the first operand—the object on the left of the +
operator. Special methods are methods that allow objects to be used with several operators and built-in functions. The special method names start and end with double underscores, leading to their informal name of dunder methods. I'll be writing in more detail about classes in the near future.
In the expressions you tried to evaluate above, the first operand is an integer in one example and a string in the other. This should explain why the error messages are different, right?
Yes, but only in part.
Let's start with the version where the string is the first operand: "5" + 5
This expression is the same as the following:
This is the same error message you get when you try to evaluate "5" + 5
. So, what's the whole fuss, you may be thinking?
Let's try the same with the expression in which the integer comes first: 5 + "5"
But before we can get to the main point of this discussion, you encounter an issue:
There's the 'inconvenience' of a SyntaxError
since the .
after a number is used to denote floats and not to access attributes of the int
class. There are a few workarounds to this. Here's the clearest one:
You no longer need to use the integer literal 5
directly to call the __add__()
special method. Great! That problem is solved.
However, you don't get the same error message as when you evaluate 5 + "5"
. When you call the __add__()
method directly, it returns NotImplemented
. This is a special value and the only instance of the NotImplementedType
!
We'll soon carry on down the path this leads us. But first, you may be curious about the workarounds I mentioned earlier to deal with the issue that you can't write 5.__add__("5")
. You've seen the solution in which you define a variable name first. You can also call __add__()
directly by using the class name:
You need to include both objects as arguments since you're not calling __add__()
as a method on an integer object. The other option is a "cheat" I've only learned about recently. You can add a space after the integer literal and call the method without the need for a variable name:
Note the space between 5
and .
in this version. It doesn't matter which option you choose. They do the same thing.†
† Edit: Thanks to those who pointed out there’s another option: (5).__add__(“5”)