Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #11943 > unrolled thread
| Started by | Laurent <laurent.payot@gmail.com> |
|---|---|
| First post | 2011-08-21 09:52 -0700 |
| Last post | 2011-08-21 20:35 -0400 |
| Articles | 9 — 7 participants |
Back to article view | Back to comp.lang.python
relative speed of incremention syntaxes (or "i=i+1" VS "i+=1") Laurent <laurent.payot@gmail.com> - 2011-08-21 09:52 -0700
Re: relative speed of incremention syntaxes (or "i=i+1" VS "i+=1") woooee <woooee@gmail.com> - 2011-08-21 09:59 -0700
Re: relative speed of incremention syntaxes (or "i=i+1" VS "i+=1") Laurent <laurent.payot@gmail.com> - 2011-08-21 10:03 -0700
Re: relative speed of incremention syntaxes (or "i=i+1" VS "i+=1") Irmen de Jong <irmen@-NOSPAM-xs4all.nl> - 2011-08-21 19:14 +0200
Re: relative speed of incremention syntaxes (or "i=i+1" VS "i+=1") Hans Mulder <hansmu@xs4all.nl> - 2011-08-21 19:57 +0200
Re: relative speed of incremention syntaxes (or "i=i+1" VS "i+=1") Nobody <nobody@nowhere.com> - 2011-08-21 22:07 +0100
Re: relative speed of incremention syntaxes (or "i=i+1" VS "i+=1") Laurent Payot <laurent.payot@gmail.com> - 2011-08-21 16:49 -0700
Re: relative speed of incremention syntaxes (or "i=i+1" VS "i+=1") Terry Reedy <tjreedy@udel.edu> - 2011-08-21 22:15 -0400
Re: relative speed of incremention syntaxes (or "i=i+1" VS "i+=1") Terry Reedy <tjreedy@udel.edu> - 2011-08-21 20:35 -0400
| From | Laurent <laurent.payot@gmail.com> |
|---|---|
| Date | 2011-08-21 09:52 -0700 |
| Subject | relative speed of incremention syntaxes (or "i=i+1" VS "i+=1") |
| Message-ID | <8c606fc1-0aa8-4113-b607-e46ad6f3d649@glegroupsg2000goo.googlegroups.com> |
Hi Folks,
I was arguing with a guy who was sure that incrementing a variable i with "i += 1" is faster than "i = i + 1". I couldn't tell if he was right or wrong so I did a little benchmark with the very useful timeit module.
Here are the results on my little Linux Eeepc Netbook (using Python 3.2):
Computing, please wait...
Results for 1000000 times "i = i + 1":
0.37591004371643066
0.3827171325683594
0.37238597869873047
0.37305116653442383
0.3725881576538086
0.37294602394104004
0.3712761402130127
0.37357497215270996
0.371567964553833
0.37359118461608887
Total 3.7396 seconds.
Results for 1000000 times "i += 1":
0.3821070194244385
0.3802030086517334
0.3828878402709961
0.3823058605194092
0.3801591396331787
0.38340115547180176
0.3795340061187744
0.38153910636901855
0.3835160732269287
0.381864070892334
Total 3.8175 seconds.
==> "i = i + 1" is 2.08% faster than "i += 1".
I did many tests and "i = i + 1" always seems to be around 2% faster than "i += 1". This is no surprise as the += notation seems to be a syntaxic sugar layer that has to be converted to i = i + 1 anyway. Am I wrong in my interpretation?
Btw here's the trivial Python 3.2 script I made for this benchmark:
import timeit
r = 10
n = 1000000
s1 = "i = i + 1"
s2 = "i += 1"
t1 = timeit.Timer(stmt=s1, setup="i = 0")
t2 = timeit.Timer(stmt=s2, setup="i = 0")
print("Computing, please wait...")
results1 = t1.repeat(repeat=r, number=n)
results2 = t2.repeat(repeat=r, number=n)
print('\nResults for {} times "{}":'.format(n, s1))
sum1 = 0
for result in results1:
print(result)
sum1 += result
print("Total {:.5} seconds.".format(sum1))
print('\nResults for {} times "{}":'.format(n, s2))
sum2 = 0
for result in results2:
print(result)
sum2 += result
print("Total {:.5} seconds.".format(sum2))
print('\n==> "{}" is {:.3}% faster than "{}".'.format(s1,(sum2 / sum1) * 100 - 100, s2))
Comments are welcome...
[toc] | [next] | [standalone]
| From | woooee <woooee@gmail.com> |
|---|---|
| Date | 2011-08-21 09:59 -0700 |
| Message-ID | <4af56750-aae1-4e93-8100-3a913f9901bf@a10g2000prn.googlegroups.com> |
| In reply to | #11943 |
as the += notation seems to be a syntaxic sugar layer that has to be converted to i = i + 1 anyway. That has always been my understanding. The faster way is to append to a list as concatenating usually, requires the original string, accessing an intermediate block of memory, and the memory for the final string. x_list.append(value) to_string = "".join(x_list)
[toc] | [prev] | [next] | [standalone]
| From | Laurent <laurent.payot@gmail.com> |
|---|---|
| Date | 2011-08-21 10:03 -0700 |
| Message-ID | <e57fb85a-8a3b-4572-b8b7-68d856a092ca@glegroupsg2000goo.googlegroups.com> |
| In reply to | #11944 |
Well I agree with you about string concatenation, but here I'm talking about integers incrementation...
[toc] | [prev] | [next] | [standalone]
| From | Irmen de Jong <irmen@-NOSPAM-xs4all.nl> |
|---|---|
| Date | 2011-08-21 19:14 +0200 |
| Message-ID | <4e513ceb$0$23863$e4fe514c@news2.news.xs4all.nl> |
| In reply to | #11945 |
On 21-08-11 19:03, Laurent wrote:
> Well I agree with you about string concatenation, but here I'm talking about integers incrementation...
Seems the two forms are not 100% identical:
>>> import dis
>>> def f1(x):
... x=x+1
...
>>> def f2(x):
... x+=1
...
>>>
>>> dis.dis(f1)
2 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1)
6 BINARY_ADD
7 STORE_FAST 0 (x)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> dis.dis(f2)
2 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1)
6 INPLACE_ADD
7 STORE_FAST 0 (x)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>>
What the precise difference (semantics and speed) is between the
BINARY_ADD and INPLACE_ADD opcodes, I dunno. Look in the Python source
code or maybe someone knows it from memory :-)
Irmen
[toc] | [prev] | [next] | [standalone]
| From | Hans Mulder <hansmu@xs4all.nl> |
|---|---|
| Date | 2011-08-21 19:57 +0200 |
| Message-ID | <4e51471e$0$23880$e4fe514c@news2.news.xs4all.nl> |
| In reply to | #11946 |
On 21/08/11 19:14:19, Irmen de Jong wrote: > What the precise difference (semantics and speed) is between the > BINARY_ADD and INPLACE_ADD opcodes, I dunno. Look in the Python source > code or maybe someone knows it from memory :-) There is a clear difference in semantics: BINARY_ADD always produces a new object, INPLACE_ADD may modify its left-hand operand in situ (if it's mutable). Integers are immutable, so for integers the semantics are the same, but for lists, for example, the two are different: >>> x = [2, 3, 5, 7] >>> y = [11, 13] >>> x+y [2, 3, 5, 7, 11, 13] >>> x [2, 3, 5, 7] # x still has its original value >>> x += y >>> x [2, 3, 5, 7, 11, 13] # x is now modified >>> For integers, I would not expect a measurable difference in speed. Hope this helps, -- HansM
[toc] | [prev] | [next] | [standalone]
| From | Nobody <nobody@nowhere.com> |
|---|---|
| Date | 2011-08-21 22:07 +0100 |
| Message-ID | <pan.2011.08.21.21.07.55.886000@nowhere.com> |
| In reply to | #11943 |
On Sun, 21 Aug 2011 09:52:23 -0700, Laurent wrote: > I did many tests and "i = i + 1" always seems to be around 2% faster > than "i += 1". This is no surprise as the += notation seems to be a > syntaxic sugar layer that has to be converted to i = i + 1 anyway. Am I > wrong in my interpretation? It depends. If the value on the left has an __iadd__ method, that will be called; the value will be updated in-place, so all references to that object will be affected: > import numpy as np > a = np.zeros(3) > b = a > a array([ 0., 0., 0.]) > b array([ 0., 0., 0.]) > a += 1 > a array([ 1., 1., 1.]) > b array([ 1., 1., 1.]) If the value on the left doesn't have an __iadd__ method, then addition is performed and the name is re-bound to the result: > a = a + 1 > a array([ 2., 2., 2.]) > b array([ 1., 1., 1.]) If you're writing code which could reasonably be expected to work with arbitrary "numeric" values, you should decide which to use according to whether in-place modification is appropriate rather than trivial performance differences. If a difference of a few percent is significant, Python is probably the wrong language in the first place.
[toc] | [prev] | [next] | [standalone]
| From | Laurent Payot <laurent.payot@gmail.com> |
|---|---|
| Date | 2011-08-21 16:49 -0700 |
| Message-ID | <62dbc2b2-36bd-420c-a5f5-3a6aefcdc139@glegroupsg2000goo.googlegroups.com> |
| In reply to | #11964 |
I made Python my language of choice because of its readability and simpleness, and not because of its speed. But it's always good to know what is the fastest sometimes when you don't want to write a module in C. So I was just wondering if there was a difference. There is, of a few percent. Anyway I will keep on using the 2% slower "i += 1" because for me that's less prone to errors because you write the variable only once, and that's more important than speed.
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-08-21 22:15 -0400 |
| Message-ID | <mailman.298.1313979609.27778.python-list@python.org> |
| In reply to | #11973 |
On 8/21/2011 7:49 PM, Laurent Payot wrote: > I made Python my language of choice because of its readability and > simpleness, and not because of its speed. But it's always good to > know what is the fastest sometimes when you don't want to write a > module in C. So I was just wondering if there was a difference. There > is, of a few percent. Anyway I will keep on using the 2% slower "i += > 1" because for me that's less prone to errors because you write the > variable only once, and that's more important than speed. For longer variable names, it is also easier and faster to read once one gets used to the idiom. number_of_chars += 1 # versus number_of_chars = number_of_chars + 1 Not repeating was a major reason for the addition. -- Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-08-21 20:35 -0400 |
| Message-ID | <mailman.294.1313974278.27778.python-list@python.org> |
| In reply to | #11964 |
On 8/21/2011 5:07 PM, Nobody wrote:
> If the value on the left has an __iadd__ method, that will be called;
Correct
> the value will be updated in-place,
Not necessarily correct. The target is rebound to the return from the
__iadd__ method. Augmented *assignment* is always assignment. This trips
up people who try
t = (1, [])
t[1] += [1,2] # which *does* extend the array, but raises
TypeError: 'tuple' object does not support item assignment
# instead of
t[1].extend([1,2]) # which extends without raising an error
*IF* (and only if) the target object is mutable, then the __iadd__ may
optionally mutate the target object. But the rebinding takes place
nonetheless. Numbers, the subject of this thread, are not mutable and
are not 'updated in-place'
class test:
def __init__(self, n):
self.n = n
def __iadd__(self, other):
return test(self.n + other.n)
def __repr__(self):
return repr(self.n)
r = test(1)
t = r
t += r
print(r, t)
# 1,2
That said, there is normally no reason to write an __ixxx__ method
unless instances are mutable and the operation can be and is done in
place therein. So the class above is for illustrative purposes only. A
saner example is the following, which treats test examples as mutable
number containers rather than as immutable surrogates.
class test:
def __init__(self, n):
self.n = n
def __add__(self, other):
return test(self.n + other.n)
def __iadd__(self, other):
n = self.n + other.n
self.n = n
return n
def __repr__(self):
return repr(self.n)
r = test(1)
t = r
t += r
print(r, t)
# 2 2
The interpreter cannot enforce that 'x += a' have the same effect as 'x
= x+a', but it would break normal expectations to make the two different.
> so all references to that object will be affected:
Only if the target object is mutable and is mutated by the optional
augmented assignment __ixxx__ methods.
> > import numpy as np
> > a = np.zeros(3)
Numpy arrays meet the qualification above.
> If the value on the left doesn't have an __iadd__ method, then addition is
> performed and the name is re-bound to the result:
As is also done with the results of __ixxx__ methods.
--
Terry Jan Reedy
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web