I am writing Fibonacci code in python. The below solution is mine.
While the other below solution is from python.org.
Can anyone tell me why it yields a different answer even though the logic of assigning the variables is the same?
Those two programs are not equivalent. The right hand side of the equals (=) is evaluated all together.
Doing:
a=b
b=a+b
Is different from:
a,b = b,a+b
This is in reality the same as:
c = a
a = b
b = b + c
Your example is actually covered on the Python documentation:
The first line contains a multiple assignment: the variables a and b simultaneously get the new values 0 and 1. On the last line this is used again, demonstrating that the expressions on the right-hand side are all evaluated first before any of the assignments take place. The right-hand side expressions are evaluated from the left to the right.
The lines
a = b # Assigns the value of 'b' to 'a'
b = a + b # Adds the new value of 'a' to 'b'
whereas,
a, b = b, a+b Assigns the value of b to a. Adds the existing value of a to b.
The reason it works in the second example is becasue the a=b doesn't evaluate until both are done. So when it gets to the b=a+b part, a is still its previous value. In your first example you are overwriting a before using it. In python when you declare variables in this way you are actually using them as tuples. This means that until the whole line is completed they retain their original values. Once the tuple is unpacked they are overwritten.
I see extra tabs in your solution and also logic of your program is wrong. As far as I understood by writing fib(5) you want 5th fibonacci in the series (which is 5) not a number which is less than 5 (which is 3).
a=b
b=a+b
and
a,b = b,a+b
are not equal.
Look at the code below.
def fibonacci(num):
a,b=0,1;
counter = 2;
while(a<=):
a,b = b,a+b
counter += 1
return b
print fibonacci(5)
Related
I know about tuple unpacking but what is this assignment called where you have multiple equals signs on a single line? a la a = b = True
It always trips me up a bit especially when the RHS is mutable, but I'm having real trouble finding the right keywords to search for in the docs.
It's a chain of assignments and the term used to describe it is...
- Could I get a drumroll please?
Chained Assignment.
I just gave it a quite google run and found that there isn't that much to read on the topic, probably since most people find it very straight-forward to use (and only the true geeks would like to know more about the topic).
In the previous expression the order of evaluation can be viewed as starting at the right-most = and then working towards the left, which would be equivalent of writing:
b = True
a = b
The above order is what most language describe an assignment-chain, but python does it differently. In python the expression is evaluated as this below equivalent, though it won't result in any other result than what is previously described.
temporary_expr_result = True
a = temporary_expr_result
b = temporary_expr_result
Further reading available here on stackoverflow:
How do chained assignments work? python
#refp's answer is further supported with this output using the dis (disassembly) module:
>>> def a(x):
... g = h = x
...
>>> import dis
>>> dis.dis(a)
2 0 LOAD_FAST 0 (x)
3 DUP_TOP
4 STORE_FAST 1 (g)
7 STORE_FAST 2 (h)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
The RHS is retrieved and duplicated, then stored into the destination variables left-to-right (try this yourself with e = f = g = h = x).
Some other posters have been confused if the RHS is a function call, like a = b = fn() - the RHS is only evaluated once, and then the result assigned to each successive variable. This may cause unwanted sharing if the returned value is a mutable, like a list or dict.
For those using threading, it is useful to note that there is no "atomicity" implied by the chained assignment form over multiple explicit assignment statements - a thread switch could occur between the assignments to g and h, and another thread looking at the two of them could see different values in the two variables.
From the documentation, 7.2. Assignment statements, g and h being two target lists, x being the expression list:
assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)
An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.
OK, "chained assignment" was the search term I was after, but after a bit more digging I think it's not strictly correct. but it is easier to search for than "a special case of the assignment statement".
The Wikipedia article senderle linked to says:
In Python, assignment statements are not expressions and thus do not
return a value. Instead, chained assignments are a series of
statements with multiple targets for a single expression. The
assignments are executed left-to-right so that i = arr[i] = f()
evaluates the expression f(), then assigns the result to the leftmost
target, i, and then assigns the same result to the next target,
arr[i], using the new value of i.
Another blog post says:
In Python, assignment statements do not return a value. Chained
assignment (or more precisely, code that looks like chained assignment
statements) is recognized and supported as a special case of the
assignment statement.
This seems the most correct to me, on a closer reading of the docs - in particular (target_list "=")+ - which also say
An assignment statement evaluates the expression list ... and assigns
the single resulting object to each of the target lists, from left to
right.
So it's not really "evaluated from right-most to left" - the RHS is evaluated and then assigned from left-most target to right - not that I can think of any real-world (or even contrived) examples where it would make a difference.
got bitten by python's Chained Assignment today, due to my ignorance. in code
if l1.val <= l2.val:
tail = tail.next = l1 # this line
l1 = l1.next
what I expected was
tail.next = l1
tail = tail.next
# or equivalently
# tail = l1
whereas I got below, which produce a self loop in the list, leave me in a endless loop, whoops...
tail = l1
tail.next = l1 # now l1.next is changed to l1 itself
since for a = b = c,
one way (python, for example) equivalent to
tmp = evaluate(c)
evaluate(a) = tmp
evaluate(b) = tmp
and have equal right operand for two assignment.
the other (C++, for example) equivalent to
evaluate(b) = evaluate(c)
evaluate(a) = evaluate(b)
since in this case a = b = c is basically
b = c
a = b
and two right hand operand could be different.
That why similar code works well in C++.
I am trying to understand the code provided on the Python.org tutorial in section 3.2
a, b = 0, 1
>>> while b < 10:
... print(b)
... a, b = b, a+b
The code above results in the sequence as follows:
1
1
2
3
5
8
My questions are as follows:
Why do the numbers appear vertically and not horizontally like a print statement generally does? I know you can force the numbers to appear horizontally but want to understand why that is not the default.
Most importantly, how is the python logic working? I understand its the fibonacci sequence but you're only asking the code to print "b". It should just print a+b over and over again, should it not (resulting in 1 being printed over and over again)? I don't understand how the logic within python progresses the sequence.
Any help is much appreciated. Thank you.
The python print statement by default generates a newline after each print.
This causes each printed item to appear on its own line. If you print a literal newline, you get two blank lines:
>>> print "\n"
>>>
Most importantly, how is the python logic working? I understand its
the fibonacci sequence but you're only asking the code to print "b".
It should just print a+b over and over again, should it not (resulting
in 1 being printed over and over again)?
This line:
a, b = b, a+b
evaluates the expressions b and a+b. If b=1 and a=0, then this results in the tuple (1, 1). That tuple is then split into its two components and assigned respectively to the variables a and b. So at the end of the first iteration, a and b each get the value 1. This is ultimately equivalent to the successive operations
tmp = b
b = a + b
a = tmp
but notice that here we have to create a temp variable to hold the original value of b. This is because the one-liner evaluates both of the expressions on its right-hand side before it assigns to the variables named on the left-hand side.
First of all your code would be quite simple if you used parentheses. The code a,b is a tupel:
(a,b)=(0,1)
Let's interpret the code line per line:
While b<10: #b=1
print(b) #output:1
(a,b) = (a,a+b) # a=1, b=1
Now the next iteration:
While b<10: #b=1
print(b) #output:1
(a,b) = (a,a+b) # a=1, b=2
And the next:
While b<10: #b=1
print(b) #output:2
(a,b) = (a,a+b) # a=2, b=3
And so on....
You will get
1
1
2
3
5
8
But each number in a separate line because print function add '\n'. So the output is "vertical".
I am new to python and I have really poor expiriences with other codes.
For the most of you a stupid question but somewhere I should start.
def fib(n):
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
I don't understand why one should enter a, b = b, a+b
I see and understand the result and I can conclude the basic algorithm but I don't get the real understanding of what is happening with this line and why we need it.
Many thanks
This line is executed in the following order:
New tuple is created with first element equal to b and second to a + b
The tuple is unpacked and first element is stored in a and the second one in b
The tricky part is that the right part is executed first and you do not need to use temporary variables.
The reason you need it is because, if you update a with a new value, you won't be able to calculate the new value of b. You could always use temporary variables to keep the old value while you calculate the new values, but this is a very neat way of avoiding that.
It's called sequence unpacking.
In your statement:
a, b = b, a + b
the right side b, a + b creates a tuple:
>>> 8, 5 + 8
(8, 13)
You then assign this to the left side, which is also a tuple a, b.
>>> a, b = 8, 13
>>> a
8
>>> b
13
See the last paragraph the documentation on Tuples and Sequences:
The statement t = 12345, 54321, 'hello!' is an example of tuple packing: the values 12345, 54321 and 'hello!' are packed together in a tuple. The reverse operation is also possible:
>>> x, y, z = t
This is called, appropriately enough, sequence unpacking and works for any sequence on the right-hand side. Sequence unpacking requires the list of variables on the left to have the same number of elements as the length of the sequence. Note that multiple assignment is really just a combination of tuple packing and sequence unpacking.
I'm playing with for loops in Python and trying to get used to the way they handle variables.
Take the following piece for code:
a=[1,2,3,4,5]
b=a
b[0]=6
After doing this, the zeroth element of both b and a should be 6. The = sign points a reference at the array, yes?
Now, I take a for loop:
a=[1,2,3,4,5]
for i in a:
i=6
My expectation would be that every element of a is now 6, because I would imagine that i points to the elements in a rather than copying them; however, this doesn't seem to be the case.
Clarification would be appreciated, thanks!
Everything in python is treated like a reference. What happens when you do b[0] = 6 is that you assign the 6 to an appropriate place defined by LHS of that expression.
In the second example, you assign the references from the array to i, so that i is 1, then 2, then 3, ... but i never is an element of the array. So when you assign 6 to it, you just change the thing i represents.
http://docs.python.org/reference/datamodel.html is an interesting read if you want to know more about the details.
That isn't how it works. The for loop is iterating through the values of a. The variable i actually has no sense of what is in a itself. Basically, what is happening:
# this is basically what the loop is doing:
# beginning of loop:
i = a[0]
i = 6
# next iteration of for loop:
i = a[1]
i = 6
# next iteration of for loop:
i = a[2]
i = 6
# you get the idea.
At no point does the value at the index change, the only thing to change is the value of i.
You're trying to do this:
for i in xrange(len(a)):
a[i] = 6 # assign the value at index i
Just as you said, "The = sign points a reference". So your loop just reassigns the 'i' reference to 5 different numbers, each one in turn.
the second unpacking is not working with print, what is the reason?
for a in stok.iteritems():
... c, b = a
... print c, b
this one is valid
but this one is not
for a in stok.iteritems():
... print c, b = a
You can't do an assignment (a = b) inside a print statement. They're both statements, so they have to be done separately.
If it helps, you can do: for c, b in stok.iteritems():.
The reason is that c, b = a is a statement and not an expression (i.e., it does something, but doesn't have a value) and therefore you can't print it.
Does not make much sense. You want
for a in stok.iteritems():
... print a
You can not mix assignments within a print...why would you think that this should work? Inventing new syntax?
= is assignment. I'm not sure what you are trying to achieve in the second piece of code, but it doesn't make sense: are you trying to print or are you trying to assign? You cannot print and assign in the same statement.
If you want to compare two numbers, use ==. For example:
print a == b
will tell you whether a and b are equal or not.