This question already has answers here:
Why does += behave unexpectedly on lists?
(9 answers)
Closed 1 year ago.
I'm trying to learn coding through some tutorials and encountered something curious as I'm going over operators. The basic ones I get, but some others (like *= here) throw me off.
a = 1
b = a
a *= 2
print(a)
print(b)
Output
2
1
But when a is an array, this happens:
a = np.array([1, 2, 3, 3, 5, 5])
b = a
a *= 2
print(a)
print(b)
Output
[2 4 6 6 10 10]
[2 4 6 6 10 10]
Any insight as to why this happens? I can't really find much about it. The only thing I came across was "coercion rules"; does the second instance happen because a is being assigned to an array but then to an integer? Or is it a matter of the print statement order?
It's probably trivial but I'm just curious, thanks!
The Simple answer to your question is,
There are two kinds of objects in Python: Mutable objects and Immutable objects. The value of a mutable object can be modified in place after it’s creation, while the value of an immutable object cannot be changed.
Immutable(Not Modifiable) Object: int, float, long, complex, string tuple, bool
Mutable(Modifiable) Object: list, dict, set, byte array, user-defined classes.
So,here in your case firstly a and b are immutable objects as it belongs to class int in python,"b=a" means b is pointing towards a address,and as you update value of a to a*=2, the value is store on new memory location, but b is still pointing towards older address, thats why b is not showing changed value of a.
For more understanding of memory management in python, please read this blog, thankyou :)
https://medium.com/#tyastropheus/tricky-python-i-memory-management-for-mutable-immutable-objects-21507d1e5b95
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
Doing something like
a = b = 5
a
Out[63]: 5
b
Out[64]: 5
It seems to work without any problems, I can't imagine any drawbacks. I can't find any example of this out there, nor directions on whether this should be used. Are there reasons to not do this?
With this code, you won't run into any issues since you're assigning a number, and numbers are immutable.
Compare that to when a mutable value is used though:
a = b = [] # Mutable list
a.append(1) # Mutate mutable list
print(a, b) # [1] [1] # Oops
So, be careful with this. Only use it if both variables referring to the same object isn't problematic.
I'll clarify though, it isn't the fact that the object is mutable that's the problem, it's the fact that as a mutable object, it's capable of being mutated, and that mutation is problematic. It's perfectly fine to use this way if you "treat the lists as immutable":
a = b = []
# Some other code
a = [1] # Maybe these are conditional reassignments in a loop or something
b = [2]
print(a, b) # [1] [2]
Although, if you're using lists like this, you'd likely be better off using a tuple or other immutable object instead.
As pointed out by #juanpa.arrivillaga in the comments, this results in both variables sharing the same object. In your example this won't matter, but there are cases where it will.
a = b = []
a.append(1)
print(b)
It depends, if its a simple assignment to integers, then it works.
But this fails for others. Lets say you instantiate to a list
a = b = [2,3]
Now this actually create one object on memory, and both a and b share that.
So if you change the value of a, it will be reflected on b. Which is not what you want. So its better to stick with the one assignment per line.
>> a[1] = 0
>> print(b)
[2,0]
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 3 years ago.
a=[1] # here is a comment to the right
print("as expected, a=", a)
b=a
print("as expected, b=", b)
a[0]=2
print("as expected, now a=", a)
print("NOT EXPECTED TO CHANGE now b=", b)
lists are mutable ... both a and b point to the same list, so changing a will also change b
if you do not want this behaviour assign a copy of a to b
b = a[:]
if you had used an immutable datatype (like a string or number) when you change it it assigns a completely new variable to b and works ... but mutable datatypes wont work like this
In python (as in many languages, with the notable exception of C/C++), names are references to values. When you write a = b, you make a refer to the same value as b, you don't copy its contents.
Use b = list(a) to create a copy (or see deepcopy for more complex objects)
This question already has answers here:
The `is` operator behaves unexpectedly with non-cached integers
(2 answers)
Closed 1 year ago.
x=300
y=300
print(id(x),id(y))
a=[300,300]
print(id(a[0]),id(a[1]))
On executing above code I get different addresses for x and y but the same address for a[0] and a[1]. Can anyone tell me why that is happening?
Take a look at below example:
>>> a=256
>>> b=256
>>> print(id(a),id(b))
(31765012, 31765012)
>>>
>>> c=257
>>> d=257
>>> print(id(c),id(d))
(44492764, 44471284)
>>>
This will help you understand the unexpected behavior for integers. Whenever you create a int in range -5 to 256 you actually just get back a reference to the existing object. This is called Integer Caching in python.
In CPython, the C-API function that handles creating a new int object is PyLong_FromLong(long v). see the documentation on this link
EDIT: Now coming to the list. For the same list elements (larger integers) you are getting same id's because list is created at once or you can say in one go.
You can achieve similar behavior with integers as well, see below example with parallel assignment.
>>>
>>> a,b = 300,300
>>>
>>> print(id(a),id(b))
(36132288, 36132288)
>>>
Hope this will clear your doubts.
This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 6 years ago.
Much has been written about python pass-by-object-reference. But it is confusing to read threads like this or this.
In those threads, some say mutability is important, while others say that mutable or immutable objects are handled the same way.
I have a simple question, why are the contents of a not modified in the first snippet of code and modified in the second? According to this explanation of pass-by-object-reference, shouldn't the contents of the reference be modified in both cases?
def fn(b):
b += 1
a = 2
fn(a)
print(a)
def fn(b):
b += [4]
a = [2]
fn(a)
print(a)
shouldn't the contents of the reference be modified in both cases?
No, since int objects are immutable.
You don't even need functions to demonstrate this.
Consider the following:
a = 1
print(id(a))
a += 1
print(id(a))
>> 496418832
496418848
We are obviously getting a new object.
Compare to:
a = [1]
print(id(a))
a += [2]
print(id(a))
>> 36641608
36641608
Note a is still referencing the same object in this case.
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 7 years ago.
As the title say, one variable is causing another to become zero for no apparent reason. Here is my code, shorted with a ton of print statements trying to figure out what's going on.
for i in range(1, number_of_layers):
a_nt[i] = 0.5 * ((dia / 2) ** 2) * (theta_t[i] - sin(theta_t[i]))
print("ant 1 ", a_nt[i])
I assign a value to a_nt and later decide how that value will be used in an if state to assign it to a_t. The code goes into the else portion.
else:
print("ant 2 ", a_nt[i])
a_t[i] = a_nt[i]
print("at 1 ", a_t[i])
y_t[i] = y_nt[i]
print("at 2 ", a_t[i])
theta_c[i] = 0
print("at 3 ", a_t[i])
Python prints out:
ant 1 0.005738905060148785
ant 2 0.005738905060148785
at 1 0.005738905060148785
at 2 0.005738905060148785
at 3 0
For a reason that I cannot determine, a_t becomes zero after I assign theta_c a value of zero. I'm relatively new to python, but this is driving me insane!
If you make an assignment like theta_c = a_t, then you're not actually copying the array, you're merely referencing the same array with another variable.
Thus, when you change theta_c, you're also changing a_t. You should be probably taking a shallow copy instead:
theta_c = list(a_t)
Of course, depending on the situation, even a shallow copy may not be sufficient, but in this case it will probably do the trick.