I'm reading Learning Python 5th edition and I need some more explanation on this paragraph:
The __add__ method of strings, for example, is what really performs concatenation; Python maps the first of the following to the second internally, though you shouldn't usually use the second form yourself( it's less intuitive, and might even run slower):
>>> S+'NI!'
'spamNI!'
>>> S.__add__('NI!')
'spamNI!'
so my question is, why would it run slower?
>>> def test(a, b):
... return a + b
...
>>> def test2(a, b):
... return a.__add__(b)
...
>>> import dis
>>> dis.dis(test)
2 0 LOAD_FAST 0 (a)
3 LOAD_FAST 1 (b)
6 BINARY_ADD
7 RETURN_VALUE
>>> dis.dis(test2)
2 0 LOAD_FAST 0 (a)
3 LOAD_ATTR 0 (__add__)
6 LOAD_FAST 1 (b)
9 CALL_FUNCTION 1
12 RETURN_VALUE
1 BINARY_ADD instruction instead of 2 instructions: LOAD_ATTR and CALL_FUNCTION. And since BINARY_ADD does (almost) the same thing (but in C) then we can expect it to be (slightly) faster. The difference will be hardly noticable though.
Side note: so this is similar to how assembly works. Often when there is a single instruction that does the same thing as a sequence of instructions it will perform better. For example in x64 LEA instruction can be replaced with a sequence of other instructions. But they won't perform as well.
But there's a catch (which explains why I've started talking about x64 assembly). Sometimes a single instruction actually performs worse. See the infamous LOOP instruction. There may be many reasons for such a counterintuitive behaviour, like: a bit different assumption, not optimized implementation, historical reasons, a bug and so on, and so on.
Conclusion: in Python + theoretically should be faster than __add__ but always measure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With