Python address allocation to variables - python

Initially variables a, b and c all have value 1 and same address. When variable a is incremented by 1 then address gets altered, while the address of variables b and c remains same. Can someone elaborate on this address allotment?
Also now when variable b is incremented by 1 and address of b now equals to address of a. Can someone please elaborate on this as well?
>>> a = 1
>>> b = a
>>> c = b
>>> a += 1
>>> print a,b,c
2 1 1
>>> id(a)
26976576
>>> id(b)
26976600
>>> id(c)
26976600
>>> b += 1
>>> print a,b,c
2 2 1
>>> id(c)
26976600
>>> id(b)
26976576
>>> id(a)
26976576

Values and memory addresses are all misleading terms. Think of objects, names and IDs. First the object 1 is assigned to the names a, b and c. So the ID of this object can be reached by all the names.
In the second step, you assign a new object, the integer 2, with other ID to the name a.
In the third step, you assign the object integer 2 to b also. This is a implementation detail of CPython, that small integers are only held once in memory, so the object, and therefore its ID, that is reached by the name b is the same as by a.

https://docs.python.org/2/c-api/int.html#c.PyInt_FromLong
The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you actually just get back a reference to the existing object.
Also, In Python, Integer comes from a immutable object: PyIntObject. Once you create a PyIntObject, you'll never change it's value, and the others is just reference.

The reason you are seeing this is because you are thinking in terms of the variables, a, b, and c being the objects, when in fact it is the integers that are the objects of your example. The memory location that you are looking at when you type id() is the location for the int object 1 and the int object 2, and not the variable names a, b, and c.
In python, names are bound to objects. This can be problematic when you have types like lists which are mutable and you try to copy them. Changing the object means that when you poll both references, you see the change propagated in both, and that isn't always what you intend, and unless you are aware of it can cause a lot of problems with debugging.
Back to your example, I added two instances of id() at the beginning to show the id's of the integer objects 1 and 2. This should clarify things for you.
>>> a = 1
>>> b = a
>>> c = a
>>> id(a)
4298174296
>>> id(b)
4298174296
>>> id(c)
4298174296
>>> id(1)
4298174296
>>> id(2)
4298174272
>>> a += 1
>>> id(a)
4298174272
>>> id(b)
4298174296
>>> id(c)
4298174296
>>> b += 1
>>> print a, b, c
2 2 1
>>> id(c)
4298174296
>>> id(b)
4298174272
>>> id(a)
>>> 4298174272
As you can see, the location for 1 and a b c are initially all the same and the location for 2 is different. Then when you change the assignment for a, it points to the location of 2, while b and c stay pointed to 1. Then when you reassign b, it points to the location for 2 as well, leaving only c pointing at 1.
Hope that clarifies it for you.

Related

Why do variables containing lists in Python act differently from say variable containing integers in terms of storing/pointing towards values? [duplicate]

List reference append code
a = [1,2,3,4,5]
b = a
b.append(6)
print(a)
print(b)
#ans:
[1,2,3,4,5,6]
[1,2,3,4,5,6]
Integer reference in int
a = 1
b = a
b +=1
print(a)
print(b)
#ans:
1
2
how reference works in python integer vs list ? in list both value are same, why is in integer section a value is not 2 ?
In Python, everything is an object. Everything is a name for an address (pointer) per the docs.
On that page you can scroll down and find the following:
Numeric objects are immutable; once created their value never changes
Under that you'll see the int type defined, so it makes perfect sense your second example works.
On the top of the same page, you'll find the following:
Every object has an identity, a type and a value. An object’s identity never changes once it has been created; you may think of it as the object’s address in memory.
Python behaves just like C and Java in that you cannot reassign where the pointer to a name points. Python, like Java, is also pass-by-value and doesn't have a pass-by-reference semantic.
Looking at your first example:
>>> a = 1
>>> hex(id(a))
'0x7ffdc64cd420'
>>> b = a + 1
>>> hex(id(b))
'0x7ffdc64cd440'
>>> print(a)
1
>>> print(b)
2
Here it is shown that the operation b = a + 1 leaves a at 1 and b is now 2. That's because int is immutable, names that point to the value 1 will always point to the same address:
>>> a = 1
>>> b = 2
>>> c = 1
>>> hex(id(a))
'0x7ffdc64cd420'
>>> hex(id(b))
'0x7ffdc64cd440'
>>> hex(id(c))
'0x7ffdc64cd420'
Now this only holds true for the values of -5 to 256 in the C implementation, so beyond that you get new addresses, but the mutability shown above holds. I've shown you the sharing of memory addresses for a reason. On the same page you'll find the following:
Types affect almost all aspects of object behavior. Even the importance of object identity is affected in some sense: for immutable types, operations that compute new values may actually return a reference to any existing object with the same type and value, while for mutable objects this is not allowed. E.g., after a = 1; b = 1, a and b may or may not refer to the same object with the value one, depending on the implementation, but after c = []; d = [], c and d are guaranteed to refer to two different, unique, newly created empty lists. (Note that c = d = [] assigns the same object to both c and d.)
So your example:
>>> a = [1, 2, 3, 4, 5]
>>> hex(id(a))
'0x17292e1cbc8'
>>> b = a
>>> hex(id(b))
'0x17292e1cbc8'
I should be able to stop right here, its obvious that both a and b refer to the same object in memory at address 0x17292e1cbc8. Thats because the above is like saying:
# Lets assume that `[1, 2, 3, 4, 5]` is 0x17292e1cbc8 in memory
>>> a = 0x17292e1cbc8
>>> b = a
>>> print(b)
'0x17292e1cbc8'
Long and skinny? You're simply assigning a pointer to a new name, but both names point to the same object in memory! Note: This is not the same as a shallow copy because no external compound object is made.

Co-assigning python variables works different with integers and sets. Why?

Suppose I co-assign two python variables to zero:
>>> x = y = 0
When I now assign to one value it changes independently of the other:
>>> y = 2
>>> x
0
>>> y
2
Now suppose I co-assign two python variables to an empty set:
>>> a = b = set([])
When I now add to one set, it changes the value of the other. Why?
>>> b.add(2)
>>> a
set([2])
>>> b
set([2])
As commments to OP answer are just implicit clues I am making them explicit:
y = 0
x = y
Names x and y reference the same int object with 0 value.
int objects are immutable. As you can't alter them, it actually doesn't
matter what object with zero value you are pointing to, if there were several.
When you assign y again with
y = 2
y now refers to a different int object with value 2.
x still refers to the old 0 value object.
If you consider mutable types like sets,
b = set()
a = b
a and b reference the same empty set object.
If you change the set object with an in-place assignment, or using an object method that changes it in-place, the object remains the same (but with its value content changed).
So you can see the changed object either through a or through b.
However, to compare apples with apples and follow the int sample, if you make
b = set() # a new empty set
b becomes a new different set empty object, while a still references the original.
>>> a = set()
>>> b = a
>>> id(a) == id(b)
True
>>> b = set()
>>> id(a) == id(b)
False
>>>
So behaviour is actually the same in both cases. But in int case you can't make changes to the object value.

How does variable copying in Python exactly work?

Why is it that:
>>> a = 1
>>> b = a
>>> a = 2
>>> print(a)
2
>>> print(b)
1
...but:
>>> a = [3, 2, 1]
>>> b = a
>>> a.sort()
>>> print(b)
[1, 2, 3]
I mean, why are variables really copied and iterators just referenced?
Variables are not "really copied". Variables are names for objects, and the assignment operator binds a name to the object on the right hand side of the operator. More verbosely:
>>> a = 1 means "make a a name referring to the object 1".
>>> b = a means "make b a name referring to the object currently referred to by a. Which is 1.
>>> a = 2 means "make a a name referring to the object 2". This has no effect on which object anything else that happened to refer to 1 now refers to, such as b.
In your second example, both a and b are names referring to the same list object. a.sort() mutates that object in place, and because both variables refer to the same object the effects of the mutation are visible under both names.
Think of the assigned variables as pointers to the memory location where the values are held. You can actually get the memory location using id.
a = 1
b = a
>>> id(a)
4298171608
>>> id(b)
4298171608 # points to the same memory location
a = 2
>>> id(a)
4298171584 # memory location has changed
Doing the same with your list example, you can see that both are in fact operating on the same object, but with different variables both pointing to the same memory location.
a = [3, 2, 1]
b = a
a.sort()
>>> id(a)
4774033312
>>> id(b)
4774033312 # Same object
in your first example you've reassigned a's value after making b's value a. so a and b carry different values.
the same would've occurred in your second example if you had reassigned a to a new sorted list instead of just sorting it in place.
a = [3,2,1]
b = a
a.sort()
print b
[1,2,3]
but...
a = [3,2,1]
b = a
sorted(a)
print b
[3,2,1]

Difference between assignment of a variable to a number and lists of numbers in Python [duplicate]

This question already has an answer here:
List vs. int assignment - "Every variable is a pointer"
(1 answer)
Closed 8 years ago.
In python if assign a list of numbers to a variable in the following way
>>>a=range(4)
>>>b=a
>>>a[2]=9
>>>b
[0,1,9,3]
but when I assign a single variable in a similar way I get the following result
>>>a=1
>>>b=a
>>>a=2
>>>b
1
Why is it that b=1 instead of b=2 as in the result from assigning the variable to a list?
In your first example, a and b are both references to the same object, a list. When you change the list, so does the output for a and b (which still point to the same list).
In your second example, you are assigning a new integer object to the name a. a and b are two different objects with different ids now. Demo:
>>> a = range(4)
>>> b = a
>>> id(a)
38845472
>>> id(b)
38845472
>>> a=1
>>> b=a
>>> id(a)
33619048
>>> id(b)
33619048
>>> b=2
>>> id(a)
33619048
>>> id(b)
33619024
Integers are immutable so to speak, that you can not change them with slicing, unlike lists:
>>> x = range(4)
>>> x
[0, 1, 2, 3]
>>> id(x)
4300734408
>>> x[0] = 5
>>> id(x)
4300734408
>>> x = 1
>>> id(x)
4299162584
>>> x+=1
>>> id(x)
4299162560
>>>
As you can see above, you can change the list, but it still has the same id. However, if you call += on an integer, the id changes.
This is exactly why although you change a, b doesn't change along with it.

how can i set a variable in a array in python?

i have the problem where i set a variable but it creates a new one instead, i am not quite sure what is going on here. I have tried using global, setting the variables first and tried to use a tupple but just can't get it working. but this is the problem:
>>> variable = 1
>>> variableList = [variable]
>>> variableList[0] = 2
>>> print(variable)
1
as you can see it variable stays 1 although i set it to 2, is there a easy way to fix this?
Doing variableList = [variable] actually created a new reference(variableList[0]) to the object 1. And when you did variableList[0] = 2, it removed one reference from 1 and assigned variableList[0] to 2. So, using an assignment you can never modify other references.
>>> import sys
>>> variable = 1000
>>> sys.getrefcount(variable)
2
>>> variableList = [variable]
>>> sys.getrefcount(variable) # Reference count increased by 1
3
>>> variableList[0] = 2
>>> sys.getrefcount(variable) #Reference count decreased by 1
2
In fact even you've used +=, that too wouldn't have affected variable because you don't modify a immutable object, you simply assign a new object to that variable name.
>>> a = 100
>>> b = a
>>> b += 10 #This too only affects b
>>> a
100
>>> b
110
But, if variable points to a mutable object and you perform some in-place operation on that object from either variable or variableList[0], then you'll see that both of them have changed.
>>> a = []
>>> b = [a]
>>> b[0].append(1) #in-place operation on a mutable object affects all references
>>> a
[1]
>>> b
[[1]]
you don't set variable. you just change variableList content.
variableList[0] it's a variable like variable so the command variableList = [variable] just copy its value.
it is just like this:
>>> a = 1
>>> b = a
>>> b = 2
>>> print(a)
1
You're reassigning the 0th element of the list (not Array), to the Integer 2, you are not overwriting the variable variable.
>>> variable = 1
>>> variableList = [variable]
>>> variableList[0] = 2
>>> print(variable)
>>> 1
>>> print(variableList)
[2]
It suggest you also look up mutability, as it's important to note that integers are immutable:
The value of some objects can change. Objects whose value can change are said to be mutable; objects whose value is unchangeable once they are created are called immutable.
When you did :variableList = [variable]
you created the first element of veribleList and made its value to balue of variable but it dont makes this first element a varible you just coppied its value so when you change variableList[0] it has nothing to do with variable

Categories