2

I was reading another page on fibonacci sequence:

How do I print a fibonacci sequence to the nth number in Python?

and I was wondering if anyone can break down what is happening and how this specific line works. I dont fully understand how "cur" and "i" is changing and such.

cur, old, i = cur+old, cur, i+1

it was part of the fibonacci function

def fib(n):
    cur = 1
    old = 1
    i = 1
    while (i < n):
        cur, old, i = cur+old, cur, i+1
    return cur
Community
  • 1
  • 1
  • `cur, old, i = cur+old, cur, i+1` is equivalent to saying `cur=cur+old`, `old=cur`, `i=i+1`. – devnull Feb 11 '14 at 23:40
  • The Python term is ["sequence [un\]packing"](http://docs.python.org/2/tutorial/datastructures.html#tuples-and-sequences), also sometimes referred to as ["destructing assignment"](http://robert-lujo.com/post/40871820711/python-destructuring). – user2864740 Feb 11 '14 at 23:50
  • That loop should really be a `for`. – user2357112 Feb 11 '14 at 23:50

2 Answers2

3

The line you gave is equivalent to this:

cur, old, i = (cur+old, cur, i+1)

which is using a technique known as unpacking*.

Below is a demonstration:

>>> x, y, z = (1, 2, 3)  # Parenthesis are optional here
>>> x
1
>>> y
2
>>> z
3
>>>  

In a longer form, your line is equivalent to this:

tmp = cur
cur = cur+old
old = tmp
i = i+1

which can be simplified to:

tmp = cur
cur += old
old = tmp
i += 1

*Note: Actually, it has quite a few names. In addition to unpacking, a very common one is multiple assignment. @user2864740 also mentioned two more names in his comment.

Community
  • 1
  • 1
3

More generally speaking, a commatized list of l-values used as an l-value in Python unpacks an iterable from the right-hand side into the parts of the left-hand side.

In your case, this means that the right-hand side creates a three-tuple of the values cur+old, cur and i+1, which is then unpacked into cur, old and i, respectively, so that it is the same as saying:

old = cur
cur = cur + old
i = i + 1

However, it is more useful, since cur isn't clobbered before old has been assigned to. It can also be used much more generally -- the left-hand side can consist of any l-values and the right-hand side can be any iterable, and you can do things like these:

a, b, c = range(3)

or

d = [0] * 10
d[3], d[7] = 1, 2

or

e, f, g = d[2:5]

In Python3, you can also used asterisk expressions to unpack "the rest" of an iterable; for instance, like this

h, *i, j = range(5)
# h will be 0, j will be 4, and i will be [1, 2, 3]

That doesn't work in Python2, however.

For the details, this is covered in section 7.2 of the language reference.

Dolda2000
  • 25,216
  • 4
  • 51
  • 92
  • I had no idea about your last use-case! So if I only want the first and last results of my generator, I can do `first, *_, last = gen(x)`? Amazing! – Adam Smith Feb 12 '14 at 00:15