I started lately to use Python instead of Matlab and I have a question to which the answer might be obvious but I can't figure it out yet.
I have the following module in python called shared_variables.py:
global a
global b
a = 2
b = 3
c = a
d = b
in my main.py script I do the following things:
import shared_variables
for i in range(1,4):
shared_variables.a += 1
shared_variables.b += 1
print 'a= ',shared_variables.a
print 'b= ',shared_variables.b
print 'c= ',shared_variables.c
print 'd= ',shared_variables.d
and the output is the following:
a= 3
b= 4
c= 2
d= 3
a= 4
b= 5
c= 2
d= 3
a= 5
b= 6
c= 2
d= 3
Basically c and d values are not updated at each iteration. How can I solve this problem? I am asking this question because I have written a longer program in which I need to share common values between different modules that i need to update at each different iteration.
The following lines set the values of the variables once (e.g., assign the current value of a to c):
a = 2
b = 3
c = a
d = b
It does not mean that c changes whenever a changes nor that d changes whenever b changes. If you want variables to change value you'll need to assign a new value to them explicitly.
Integers are immutable in Python. You can't change them.
a += 1 is a syntax sugar for a = a + 1 i.e., after the assignment a is a different int object. c is not a anymore.
If a and c were mutable objects such as lists then changing a would change c. c = a makes c and a both to refer to the same object i.e., c is a.
For example,
a = [0]
c = a
a[0] += 1
print(a, c) # -> [1] [1]
Here are nice pictures to understand the relation between names and objects in Python
c and d start out as references to the same value as a and b, not to the same memory position. Once you assign new values to a and b, the other two references won't follow.
Python values are like balloons, and variable names are like labels. You can tie a thread between the label (name) and the balloon (value), and you can tie multiple labels to a given balloon. But assignment means you tied a new balloon to a given label. The other labels are not re-tied as well, they still are tied to the original balloon.
Python integers are immutable; they remain the same balloon throughout. Incrementing a by adding 1 with the in-place addition operator (a += 1) still has to find another balloon with the result of a + 1, and tie a to the new integer result. If a was tied to a balloon representing 2 before, it'll be replaced by a new balloon representing the value 3, and a will be retied to that. You cannot take a marker to the integer balloon and erase the 2 to replace it with 3.
Related
I am fairly new to python and I just learned about tuple unpacking, so I was playing around with this concept and got a weird result.
nList = [(1,2),4,5,6]
for a in nList:
print(a)
print(b)
I was expecting my program to crash since b is not defined as a placeholder and even if it was only the first element of my list is a tuple, but instead, I got the following result:
(1, 2)
2
4
2
5
2
6
2
You have not initialized the variable b in your code, because of which it is using some garbage value of b from memory (which is 2). To avoid such scenarios you must initialize your variables with some value (or 0) in start of your code before using them.
This question already has answers here:
Multiple assignment and evaluation order in Python
(11 answers)
Closed 4 years ago.
I am new to both programming (both in general and in Python) and to this community.
Following are two versions of the Fibonacci code, one attempted by me on my own, and the other from the Python documentation. The latter works but mine does not, and the only difference I can see between the two codes is that I have reassigned "a" and "b" on different lines in the while loop, whereas the one from Python doc. has assigned them on the same line.
In fact, when I reassign new values for a and b in my code on the same line, I get the correct output - but I dont know why? Why does it matter in this case on which line the values are reassigned?
#My own version of the fibonacci code. o/p as 1 2 4 8
a, b=0,1
while b<10:
print(b, end=" ")
a=b
b=a+b
#Python's doc version which works
a, b = 0, 1
while b < 10:
print(b, end=" ")
a, b = b, a+b
In your code a gets the value of b before the summation
a = b <---- a gets updated
b = a+b <--- summation
In the doc version, a never gets an updated value before the summation as its done on the same line. Values of a and b are updated after this line.
a,b = b, a+b
Because in your version, when you are writting b=a+b, you just write before a=b so the line is b=a+a.
In the other version, there is a, b = b, a+b
But in this one, b is changing at the same time than a.
(if you want, you could say
a1, b1 = b0, a0+b0
and you line would be :
a1=b0
b1 = a1 + b0
)
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)
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.
This question already has answers here:
Python difference between mutating and re-assigning a list ( _list = and _list[:] = )
(3 answers)
Closed 19 days ago.
Following up on Reason for unintuitive UnboundLocalError behaviour (I will assume you've read it).
Consider the following Python script:
def f():
# a+=1 # 1
aa=a
aa+=1
# b+='b' # 2
bb=b
bb+='b'
c[0]+='c' # 3
c.append('c')
cc=c
cc.append('c')
d['d']=5 # Update 1
d['dd']=6 # Update 1
dd=d # Update 1
dd['ddd']=7 # Update 1
e.add('e') # Update 2
ee=e # Update 2
ee.add('e') # Update 2
a=1
b='b'
c=['c']
d={'d':4} # Update 1
e=set(['e']) # Update 2
f()
print a
print b
print c
print d # Update 1
print e # Update 2
The result of the script is:
1
b
['cc', 'c', 'c']
{'dd': 6, 'd': 5, 'ddd': 7}
set(['e'])
The commented out lines (marked 1,2) are lines that would through an UnboundLocalError and the SO question I referenced explains why. However, the line marked 3 works!
By default, lists are copied by reference in Python, therefore it's understandable that c changes when cc changes. But why should Python allow c to change in the first place, if it didn't allow changes to a and b directly from the method's scope?
I don't see how the fact that by default lists are copied by reference in Python should make this design decision inconsistent.
What am I missing folks?
UPDATES:
For completeness I also added the dictionary equivalent to the question above, i.e. I added the source code and marked the update with # Update
For further completeness I also added the set equivalent. The set's behavior is actually surprisingly for me. I expected it to act similar to list and dictionary...
Unlike strings and integers, lists in Python are mutable objects. This means they are designed to be changed. The line
c[0] += 'c'
is identical to saying
c.__setitem__(0, c.__getitem__(0) + 'c')
which doesn't make any change to what the name c is bound to. Before and after this call, c is the same list – it's just the contents of this list that have changed.
Had you said
c += ['c']
c = [42]
in the function f(), the same UnboundLocalError would have occured, because the second line makes c a local name, and the first line translates to
c = c + ['c']
requiring the name c to be already bound to something, which (in this local scope) it isn't yet.
The important thing to think about is this: what object does a (or b or c) refer to? The line a += 1 is changing which integer a refers to. Integers are immutable, so when a changes from 1 to 2, it's really the same as a = a + 1, which is giving a an entirely new integer to refer to.
On the other hand, c[0] += 'c' doesn't change which list c refers to, it merely changes which string its first element refers to. Lists are mutable, so the same list can be modified without changing its identity.