Below is the code
a =2
b = a
b = 3
print (b,a)
3 2
I expect the value of a also to change to 3 , if b is only pointing to a's memory space and does not have it's own memory.
I am sure there is a very simple explanation which i am missing.
No. Assignment copies the reference to the object, not the object itself. eg
a = [1, 2, 3]
b = a
b[0] = 5
print(a) # gives [5, 2, 3]
However,
b = a
b = 3
re-assigns b to a new integer literal, having nothing to do with a.
Also, not strictly part of your question, but see the difference between mutable and immutable objects.
b = a points b to the same object as a. But then when you do b = 3 that reassigns b to point to a different object. a is not affected.
The problem here is that you think of python variables a pointers, where is not bad at all but they don't work like that. You should think of python variables as labels to values. Also you have to think about mutable and inmutable data. Python strings and integers are inmutable, that means that python creates a new number for each operation and reassigns the variable to the new number.
As in your example:
--------------------------------
| 3 | 2 | .. |
--------------------------------
a = 2 # a points to place 1 in our example memmory block
b = a # b points to the same memmory block as a
b = 3 # b change to point to the memmory block where 3 is located, place 0
In case that:
a = 2 # a points to place 1 in our example memmory block
b = a # b points to the same memmory block as a
b += 1 # b == 2, b + 1 == 3, so b will point to a 3, a is still not modified
if you reassign a value of b, python reassigns b which has a different value and memory loc. then. printing the address with id(a) and id(b) you can see that if values are different so the memory addresses are actually different.
try in python shell :
a = 3
b = a
id(b) == id(a) #it returns True
b = 2
id(b) == id(a) #it returns False
Related
For example
b = 4
c = []
c.append(b)
print(c)
b += 2
print(c)
I was hoping I would get
4
6
but I got
4
4
Any chance I could add the element as a pointer. And then if I reference that element with c[0] I'd be referencing the b?
here c and b are different variables where c is list and b is int so if you add some on b it doesn't mean and c will be updated but if you add some number on b and append it again on c
there will be a change
b = 4
c = []
c.append(b)
print(c)
b += 2
c.append(c)
print(c)
and what you will get is
[4, 6]
and I think is clear that a c didn't change in your question
You can do that with a class:
class Number:
def __init__(self, number):
self.number = int(number)
def __str__(self):
return str(self.number)
def __repr__(self):
return self.__str__()
def __add__(self, other):
self.number = self.number + other
b = Number(4)
c = []
c.append(b)
print(c)
b += 2
print(c)
You will get:
4
6
Refer this below link to understand how the reference works in python:
How do I pass a variable by reference?
So, in short,
python objects i.e. booleans, integers, floats, strings, and tuples are immutable, which means that after you create the object and assign some value to it, you can't modify that value.
Hence, when you do b += 2, here, b will point to a new memory reference.
Proof:
>>> b=10
>>> id(b)
1734146112
>>> b+=2
>>> id(b)
1734146144
>>>
However, as #yoav mentioned above,
you can also do this by tweaking the default behaviour of Number class but beware; you should use it very carefully as you might not need this behaviour for every class.
I got this issue when trying to improve a clustering algorithm.
I need the labels to form a chain and be assigned a value when the chain terminates.
I simpler version of the problem is explained below.
A = []
B = []
C = []
C = B
B = A
A.append(0)
This gives:
A = [0], B = [0], C = []
I want something which will instantly update all the elements when an end is reached and edited.
Like I want all A,B and C to be linked together and get updated when A is changed.
Expected result:
A = [0], B = [0], C = [0] ...
(This chain can be of any length. It may even develop branches.)
How do I go about achieving this?
I put the title that way because I felt it could be done if C pointed to where A points when B = A assignment is done.
Note:
I cannot keep track of the head of the whole chain at a time. This linking variables part is done based on some other order.
Note:
This connection forms part by part. So A = B = C = [0] is not helpful.
You can do it this way:
>>> A = B = C = []
>>> A.append(0)
>>> A
[0]
>>> B
[0]
>>> C
[0]
In Python, a variable acts as a pointer to a value. When you run A = B = C = [] you are basically saying that A, B and C are pointing to the same list in memory.
Alternatively, you can do the following:
>>> A = B = []
>>> C = A
>>> C.append(0)
>>> A
[0]
>>> B
[0]
>>> C
[0]
>>> B.append(1)
>>> A
[0, 1]
>>> B
[0, 1]
>>> C
[0, 1]
References:
Thank you so much to Mad Physicist, cdrake and Rafael for your suggestions which steered me in the direction I needed to be in to reach the answer.
Answer:
The trick is to never make assignments such as C = B; B = A;, as this will cause loss of information when variables start referring to new objects and the old objects are abandoned and left for some variables to uselessly refer to.
Instead we must make each of these already declared objects to store information as to how to reach the end of the chain. This can be done by:
# Initial Declaration
A = []; B = []; C = []; D = []
# Chain Formation
C.append(B)
B.append(A)
D.append(C)
# Data Addition at Chain head
A.append("DATA")
This gives:
>>> A
['DATA']
>>> B
[['DATA']]
>>> C
[[['DATA']]]
>>> D
[[[['DATA']]]]
Now each of the variables has access to the data added at Chain Head. This data can be obtained by repeatedly entering the into the index 0 of the list till we reach an object which is not of type <class 'list'>. The implementation given below will make it clear:
def GetData(Chain):
C = Chain.copy()
while len(C) > 0 and type(C[0]) == type([]):
C = C[0]
if len(C):
return C[0]
else:
return None
>>> ( GetData(A), GetData(B), GetData(C), GetData(D) )
('DATA', 'DATA', 'DATA', 'DATA')
This way of storing information so as to direct the preceding members to the same source of information as the head of the Chain is very helpful as it can instantly relay the change of final information to the members at the back. An example which builds over the previous code is shown below:
# Initial Declaration for New Chain
P = []; Q = []
# New Chain Formation
Q.append(P)
# Old Chain Redirection
C.remove(C[0])
C.append(Q)
# Attempted Data Recovery
>>> ( GetData(A), GetData(B), GetData(C), GetData(D), GetData(P), GetData(Q) )
('DATA', 'DATA', None, None, None, None)
# Data Addition at New Chain Head
P.append((0,0))
# Attempted Data Recovery
>>> ( GetData(A), GetData(B), GetData(C), GetData(D), GetData(P), GetData(Q) )
('DATA', 'DATA', (0, 0), (0, 0), (0, 0), (0, 0))
This is my solution to the problem I was facing. Please feel free to suggest changes if needed.
Once again, Thank you to all those who directed me to this solution.
Everything in Python is object. Variables are are just names, no relation with locations.
Names refer to objects. Names are introduced by name binding operations.
Execution model: naming and binding — Python 3.7.3 documentation
Every variable in Python is just a name, which is bound to one object.
For variable in Python, nothing is constant except for the name itself.
However, variable in C is indeed a memory location.
// c
// variable a has one location
// variable b has one location, too
// they are of course different
int a, b;
// value of location of variable a will become 4
a = 4;
// location of variable b don't change
// what changed is
// value of location of variable b
// will become value of location of variable a
b = a;
# python
# variable a(just a name) is bound to object 4
a = 4
# variable b(just a name) is bound to the object which variable a is bound
b = a
# variable b(just a name) is bound to another object 6
# nothing to with variable a(just a name)
b = 6
So:
Is there a way in python to assign a variable such that it always points to the memory where its assigned right hand side points to?
Not in Python. Variables in Python just don't point to memory directly in fact. Variables are just names.
I'm new to the language and I am a bit confused about references in Python.
Consider this code:
class A:
def __init__(self, x):
self.x = x
a = A(3)
v=[a]
print(f'obj before: v[0].x={v[0].x}')
a.x = a.x + 1
print(f'obj after: v[0].x={v[0].x}')
b = 3
w=[b]
print(f'int before: w[0]={w[0]}')
b = b + 1
print(f'int after: w[0]={w[0]}')
=====================
output:
obj before: v[0].x=3
obj after: v[0].x=4
int before: w[0]=3
int after: w[0]=3
Why do the obj and int versions of the code work differently?
a = A(3)
The variable a points to an object.
v=[a]
The first element of v points to the same object.
a.x = a.x + 1
Change the attribute "x" of the object.
v still contains the same object but its attribute has changed.
b = 3
The variable b points to the object 3.
w=[b]
The first element of w also points to the object 3.
b = b + 1
b now points to what you get when you perform addition on the object 3 and the object 1, which is the object 4.
w still contains the object 3. You never changed any attributes of this object and you never changed where the first element of w points to.
When you do this, you are modifying the object a:
a.x = a.x + 1
When you are doing this, you are changing what variable b refers to:
b = b + 1
In other words, there is a big difference between b and x in the above code: b is a variable and x is an attribute of a.
Assigning something to a variable does not modify any objects, and therefore affects only the variable to which the assignment was made*, whereas setting the value of an attribute modifies the object, which can be seen in any variable which references that object.
* There are also changes in refcounts affecting garbage collector, but is not relevant now.
I was wondering about variables assignments and why is this allowed:
a = 1, 2
a = b = 1
but this is not allowed:
a, b = 1
What is the logic behind?
Thank you
I'm going to assume you might be familiar with a language like C/C++, which is a statically-typed language. This means that the type of a variable must be declared when initialising a variable (eg you'd say int a;).
In C/C++, the syntax you are trying to do is valid syntax when doing int a, b = 1; (for example), because we're initialising two variables, a and b, to be integers, where the second one we're assigning a value 1.
However, Python is a dynamically typed language - the type of the variable does not need to be declared. Thus, when we do a, b = 1, we're actually using a feature Python has which is called "unpacking". Python is trying to unpack 1 to the variables a and b - but this is not possible since 1 is just a single piece of data - it's not a list or a tuple or whatever.
Because Python is dynamically typed, we can not just initiate a variable and not give it any value (like we do in C when we do int a;). When you do a, b = 1, it's trying to iterate through 1 and assign its contents to the variables a and b. Hence, the error TypeError: 'int' object is not iterable.
The left and right side are not symmetric. In
a = 1, 2
python does packing of the right-hand side arguments. The two comma-separated arguments create a tuple, so this is equivalent to a = (1, 2)
With
a, b = 1
python tries to do unpacking. It assigns the first value of the right-hand expression to a, and then tries to assign the second value to b. Since there is no second value, this will fail. It will treat the value 1 as iterable, so will give TypeError: int is not iterable.
You should write something like a, b = 1, 2.
In the first case python assumes a is a tuple of 1 and 2
>>> a = 1, 2
>>> a
(1, 2)
But a, b = 1 you want to give values to a and b, so there must be two values for them, but you're only providing one i.e 1. If you have a iterable of length of 2 then it would work.
>>> a, b = [6, 7]
>>> a
6
>>> b
7
In python when you give two number/strings with , python interpreter thinks its a tuple
a = 1, 2
in the above line you are creating tuple object called a
a, b = 1
In the above line left hand side syntax is for a tuple , so right side it expects tuple value
so
a,b = 1,1
works
Consider the following code:
>>> b = 3
>>> def change (b):
... b = 2
...
>>> change(b)
>>> print(b)
3
I am not confused by the fact that the print statement returns 3. Here's the question: is this because of scope, or because the argument that the function takes is not related to the outside b?
The b inside change is of a different scope than b outside of change. Inside the scope of the function, it does not matter what you call the variable before you pass it in - for now, it's going to be called b. As long as you don't return b from change and assign it to your "original" b, the first one won't change.
def change(b):
b = 2
return b
change(b)
print(b) # 3
b = change(b)
print(b) # 2
You are reassigning b. It does not change the parameter. You can test this using the id() function before and after the assignement.
The scope answers are partially correct for the object type you are passing.
Check out this link for information about how python "passes by value reference"
http://stupidpythonideas.blogspot.com/2013/11/does-python-pass-by-value-or-by.html
Here is another link that explains pythons Local -> Enclosed -> Global -> Built-in scope resolution with some examples:
http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/not_so_obvious_python_stuff.ipynb#python_legb
FWIW, the behavior is slightly different if we consider mutable objects:
>>> b = [3]
>>> def change(b):
... b[0] = 2
...
>>> change(b)
>>> print(b)
[2]
>>>
You have asked quite a tricky question, in the sense that the terminology you have used in framing the question is making people give you differing and weird answers.
You've given two choices:
we have a scope issue
b inside the function isn't related to b outside the function
Well, they are both true, and they are really just two ways to say the same thing.
Forgetting about terminology for a moment, realize that there is absolutely no difference between
b = 3
def f(a):
print(a)
f(b)
and
b = 3
def f(b):
print(b)
f(b)
The parameter names in a function's signature (the def line of a function) are local to the function, no matter what names are outside the function.
Now, you probably noticed that I sidestepped the issue of assignment within a function. That's because it's harder to explain quickly, but still be understandable and memorable to someone still in the fairly early stages of learning Python (which, no offense, it seems like you are).
Here is some reading that should help you understand fundamental concepts in Python:
http://nedbatchelder.com/text/names.html
http://www.jeffknupp.com/blog/2013/02/14/drastically-improve-your-python-understanding-pythons-execution-model/
You need to look at global variables. Just add global b at the beginning of your code and function, and it should work:
>>> global b
>>> b = 3
>>> def change():
... global b
... b = 2
...
>>> b
3
>>> change()
>>> b
2
>>>
You also need to remove the b parameter from def change(b), because that makes b both local and global. You can also return b:
>>> b = 3
>>> def change(b):
... b = 2
... return b
...
>>> b
3
>>> b = change(b)
>>> b
2
It is a scoping problem. b in the function is a local variable.
globals() is dictionary which hold all global variables.
b=3
def change (a):
globals()[a] = 2
print b
# 3
change("b")
print b
# 2