Comments on: Python value swap http://eikke.com/python-value-swap/ 'cause this is what I do Tue, 04 Dec 2012 00:03:23 +0000 hourly 1 http://wordpress.org/?v=3.4.1 By: Nicolas http://eikke.com/python-value-swap/comment-page-1/#comment-20934 Nicolas Thu, 30 Apr 2009 17:03:38 +0000 http://eikke.com/?p=103#comment-20934 Hmh, rather stupid typo ;-) Thanks for noticing. Hmh, rather stupid typo ;-) Thanks for noticing.

]]>
By: Chris http://eikke.com/python-value-swap/comment-page-1/#comment-20933 Chris Thu, 30 Apr 2009 16:58:23 +0000 http://eikke.com/?p=103#comment-20933 ...: tmp = a ...: a = b ...: b = a Not that it matters, but the result of this is a = b, and b = b …: tmp = a
…: a = b
…: b = a

Not that it matters, but the result of this is a = b, and b = b

]]>
By: James Henstridge http://eikke.com/python-value-swap/comment-page-1/#comment-20733 James Henstridge Thu, 23 Apr 2009 14:27:56 +0000 http://eikke.com/?p=103#comment-20733 I guess I was wrong for modern versions of Python. It's good to see that the cleanest looking solution is now the most efficient (and seems to have been since at least 2.4). I guess I was wrong for modern versions of Python. It’s good to see that the cleanest looking solution is now the most efficient (and seems to have been since at least 2.4).

]]>
By: Nicolas http://eikke.com/python-value-swap/comment-page-1/#comment-20727 Nicolas Thu, 23 Apr 2009 08:12:44 +0000 http://eikke.com/?p=103#comment-20727 James: I think you're wrong here (in the case of swapping 2 variables). <code><pre>In [1]: def f(): ...: a = 1 ...: b = 2 ...: ...: tmp = a ...: a = b ...: b = a ...: In [2]: def g(): ...: a = 1 ...: b = 2 ...: ...: a, b = b, a ...: In [3]: %timeit f() 1000000 loops, best of 3: 568 ns per loop In [4]: %timeit g() 1000000 loops, best of 3: 546 ns per loop In [5]: %timeit f() 1000000 loops, best of 3: 591 ns per loop In [6]: %timeit g() 1000000 loops, best of 3: 543 ns per loop In [7]: %timeit f() 1000000 loops, best of 3: 588 ns per loop In [8]: %timeit g() 1000000 loops, best of 3: 515 ns per loop</pre></code> The reason is obvious when looking at the opcodes generated by the compiler (which is an optimization of the general system using tuple pack/unpack): <code><pre>In [10]: dis.dis(f) 2 0 LOAD_CONST 1 (1) 3 STORE_FAST 0 (a) 3 6 LOAD_CONST 2 (2) 9 STORE_FAST 1 (b) 5 12 LOAD_FAST 0 (a) 15 STORE_FAST 2 (tmp) 6 18 LOAD_FAST 1 (b) 21 STORE_FAST 0 (a) 7 24 LOAD_FAST 0 (a) 27 STORE_FAST 1 (b) 30 LOAD_CONST 0 (None) 33 RETURN_VALUE</pre></code> <code><pre>In [11]: dis.dis(g) 2 0 LOAD_CONST 1 (1) 3 STORE_FAST 0 (a) 3 6 LOAD_CONST 2 (2) 9 STORE_FAST 1 (b) 5 12 LOAD_FAST 1 (b) 15 LOAD_FAST 0 (a) 18 ROT_TWO 19 STORE_FAST 0 (a) 22 STORE_FAST 1 (b) 25 LOAD_CONST 0 (None) 28 RETURN_VALUE</pre></code> The unoptimized case: <code><pre>In [12]: def h(): ....: a, b, c, d = d, c, b, a ....: In [13]: dis.dis(h) 2 0 LOAD_FAST 0 (d) 3 LOAD_FAST 1 (c) 6 LOAD_FAST 2 (b) 9 LOAD_FAST 3 (a) 12 BUILD_TUPLE 4 15 UNPACK_SEQUENCE 4 18 STORE_FAST 3 (a) 21 STORE_FAST 2 (b) 24 STORE_FAST 1 (c) 27 STORE_FAST 0 (d) 30 LOAD_CONST 0 (None) 33 RETURN_VALUE</pre></code> James: I think you’re wrong here (in the case of swapping 2 variables).

In [1]: def f():
   ...:     a = 1
   ...:     b = 2
   ...:     
   ...:     tmp = a
   ...:     a = b
   ...:     b = a
   ...: 

In [2]: def g():
   ...:     a = 1
   ...:     b = 2
   ...:     
   ...:     a, b = b, a
   ...: 

In [3]: %timeit f()
1000000 loops, best of 3: 568 ns per loop

In [4]: %timeit g()
1000000 loops, best of 3: 546 ns per loop

In [5]: %timeit f()
1000000 loops, best of 3: 591 ns per loop

In [6]: %timeit g()
1000000 loops, best of 3: 543 ns per loop

In [7]: %timeit f()
1000000 loops, best of 3: 588 ns per loop

In [8]: %timeit g()
1000000 loops, best of 3: 515 ns per loop

The reason is obvious when looking at the opcodes generated by the compiler (which is an optimization of the general system using tuple pack/unpack):

In [10]: dis.dis(f)
  2           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (a)

  3           6 LOAD_CONST               2 (2)
              9 STORE_FAST               1 (b)

  5          12 LOAD_FAST                0 (a)
             15 STORE_FAST               2 (tmp)

  6          18 LOAD_FAST                1 (b)
             21 STORE_FAST               0 (a)

  7          24 LOAD_FAST                0 (a)
             27 STORE_FAST               1 (b)
             30 LOAD_CONST               0 (None)
             33 RETURN_VALUE

In [11]: dis.dis(g)
  2           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (a)

  3           6 LOAD_CONST               2 (2)
              9 STORE_FAST               1 (b)

  5          12 LOAD_FAST                1 (b)
             15 LOAD_FAST                0 (a)
             18 ROT_TWO             
             19 STORE_FAST               0 (a)
             22 STORE_FAST               1 (b)
             25 LOAD_CONST               0 (None)
             28 RETURN_VALUE

The unoptimized case:

In [12]: def h():
   ....:     a, b, c, d = d, c, b, a
   ....: 

In [13]: dis.dis(h)
  2           0 LOAD_FAST                0 (d)
              3 LOAD_FAST                1 (c)
              6 LOAD_FAST                2 (b)
              9 LOAD_FAST                3 (a)
             12 BUILD_TUPLE              4
             15 UNPACK_SEQUENCE          4
             18 STORE_FAST               3 (a)
             21 STORE_FAST               2 (b)
             24 STORE_FAST               1 (c)
             27 STORE_FAST               0 (d)
             30 LOAD_CONST               0 (None)
             33 RETURN_VALUE

]]>
By: James Henstridge http://eikke.com/python-value-swap/comment-page-1/#comment-20708 James Henstridge Thu, 23 Apr 2009 00:56:05 +0000 http://eikke.com/?p=103#comment-20708 If you benchmark it, you'll find that the first version using the temporary variable is faster than the second version. This isn't too surprising when you realise that it creates a tuple object then has to pull the values out of the tuple object and finally destroy it. This isn't to say that tuple unpacking isn't useful -- if you've already got a tuple and you want to assign its items to variables it is a very convenient language feature. If you benchmark it, you’ll find that the first version using the temporary variable is faster than the second version. This isn’t too surprising when you realise that it creates a tuple object then has to pull the values out of the tuple object and finally destroy it.

This isn’t to say that tuple unpacking isn’t useful — if you’ve already got a tuple and you want to assign its items to variables it is a very convenient language feature.

]]>
By: Nicolas http://eikke.com/python-value-swap/comment-page-1/#comment-20706 Nicolas Thu, 23 Apr 2009 00:29:40 +0000 http://eikke.com/?p=103#comment-20706 Marius: Thanks, didn't know that one! Marius: Thanks, didn’t know that one!

]]>
By: Marius Gedminas http://eikke.com/python-value-swap/comment-page-1/#comment-20704 Marius Gedminas Wed, 22 Apr 2009 23:26:18 +0000 http://eikke.com/?p=103#comment-20704 Python rules. In a rather similar way, Python lets you compare more than two values at once, e.g. 1 < x < 100. Most other programming languages would require you to split that into multiple comparisons combined with boolean operators. Python rules.

In a rather similar way, Python lets you compare more than two values at once, e.g. 1 < x < 100. Most other programming languages would require you to split that into multiple comparisons combined with boolean operators.

]]>
By: Kristof Provost http://eikke.com/python-value-swap/comment-page-1/#comment-20699 Kristof Provost Wed, 22 Apr 2009 20:09:34 +0000 http://eikke.com/?p=103#comment-20699 In case anyone cares Perl has a very similar construct: ($a, $b) = ($b, $a); In case anyone cares Perl has a very similar construct:
($a, $b) = ($b, $a);

]]>