Let's assume I execute the following:
>>> id(a)
139926795932424
>>> a
[1, 2, 3, 4]
>>> a = a + [5]
>>> id(a)
Will the last line of this script print 139926795932424? Or a new id will be assigned to a?
Will the last line of this script print 139926795932424? Or a new id will be assigned to a?
A new id will be assigned to a. Why? Because a refers to a different object.
a = a + [5] is syntactic sugar for a = a.__add__([5]), and since a.__add__([5]) returns a new object, a holds a reference to the new object rather than the old object. This can be observed with a simple example:
>>> a = [1, 2]
>>> b = a # copy the reference in a to b
>>> id(a) == id(b) # they match
True
>>> a = a + [5] # syntatic sugar for a = a.__add__([5])
>>> id(a) == id(b) # they no longer match
False
>>>
Note that in that sense, a = a + [5] and a += [5] are not identical even though they produce the same result (a = [1, 2, 5]). The first example as said above, is syntactic sugar for a = a.__add__([5]). While the second is syntactic sugar for a = a.__iadd__([5]). The difference is that the latter method - __iadd__() - does not create a new object in memory. Rather, it modifies the existing list object, and returns a reference to it. Again like previously:
>>> a = [1, 2]
>>> b = a # copy the reference in a to b
>>> id(a) == id(b) # they match
True
>>> a += [5]
>>> id(a) == id(b) # they still match, `b` has mutated too!
True
>>> b
[1, 2, 5]
From the documentation:
id(object)
Return the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
CPython implementation detail: This is the address of the object in memory.
Since you assigned a new value to a, this new object will have another id.
See more details in this question.
>>> a= [1,2,3]
>>> a
[1, 2, 3]
>>> id(a)
39384488
>>> a + [5]
[1, 2, 3, 5]
>>> id(a)
39384488
No the id() does not change as you are not creating a new instance or lifetime of the variable. See the documentation for id().
EDIT:
The above example does not reassign the variable like in the question. In that scenario it would be a new variable as a = a + [5] returns a new object.
In Python, objects are given unique identification numbers that are “guaranteed to be unique and constant for the object during its lifetime.”
In your example, the line a = a + [5] is directly changing the list a and when we call the id() function on the list, we will see a different unique id number. This essentially creates a new list (new object!)
>>> a = [1, 2, 3, 4]
>>> id(a)
140250098481992
>>> a = a + [5]
>>> id(a)
140250098532296
Related
a = [1,2,3]
b = [1,2,3]
I understand a is b is false but i can't understand a is [1,2,3] is false
I learned variable is like nickname for objects like x = 2 and id(x) == id(2)
but id(a) is not as same as id(b)...
In this case, a is an object? not a variable?
Variables are references to objects. a does not reference the same object as b. Even though the two objects are the same they have unique addresses in memory and do not depend on each other.
>>> a = b = [1,2,3]
>>> c = [1,2,3]
>>> print(a is b)
True
>>> print(a is c or b is c)
False
>>> a.remove(1)
>>> print(a)
[2, 3]
>>> print(b)
[2, 3]
>>> print(c)
[1, 2, 3]
In the case of the x = 2 and id(x) == id(2) integers are immutable and in CPython id is simply the location of an object in memory. Integers are always the same so storing the same integer several times at different addresses would be a waste of memory.
However, in general DO NOT use integers with is operator as it can lead to different results across different python implementations.
Everything in Python is an object. a is b evaluates to false because, as you know, they are not the same object. They are both instances of the List class, therefore having different locations in memory, and being completely separate in every way except their class structure, or blueprint, as you can think of it. id(a) and id(b) will reflect this, they are not the same object and will therefore not share an ID. This is a reference to their location in memory, and while IDs are not referenced pointers, they are similar in that they describe their not being the same.
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> id(a) == id(b)
False
>>> # the below is an example, every session will result in a different ID,
>>> # as it's being stored at a unique mem location each time
>>> id(a)
2770873780160
>>> id(b)
2770873412800
>>> id(a) - id(b) # simply to show the difference in location.
367360
double equals vs is in python
https://www.tutorialspoint.com/difference-between-and-is-operator-in-python
I don't understand the reason that in the first example, b is considered as a copy of a and it will change with a but not in the second example
def bubbleSort(alist):
for passnum in range(len(alist)-1,0,-1):
for i in range(passnum):
if alist[i]>alist[i+1]:
temp = alist[i]
alist[i] = alist[i+1]
alist[i+1] = temp
return alist
a=[3,2,1]
b=a
a=bubbleSort(a)
print(a)
print(b)
The output:
[1, 2, 3]
[1, 2, 3]
a=[3,2,1]
b=a
a=[1,2,3]
print(a)
print(b)
Output:
[1, 2, 3]
[3, 2, 1]
a=[3,2,1]
b=a # **here you're refrencing by memory not value**
a=bubbleSort(a)
print id(a)
print id(b)
# these both will give you same memory reference
print(a)
print(b)
In the second example when you're doing b=a you're referencing by memory, but when you did a=[1,2,3] you're associating a to a new memory reference b is still bound to the old one.
a = [3,2,1]
b=a
print id(b) #4376879184
print id(a) #4376879184
#they will be having the same id
a = [1,2,3]
#now you have assigned a new address which will have the new array
print id(b) #4376879184
print id(a) #4377341464
#they will be having different id now
In your first example - You send the 'reference' to the list which is shared between a and b (and change it).
In the second example - You explicitly change the 'reference' when stating a = [1,2,3]
If you want to fix this, return a different instance from the bubble sort function (Dont change the actual list being sent, create a new one and return it - this is a thing you do with pointers in C, less in python).
Either way read up a bit on mutable / immutable types in python - https://medium.com/#meghamohan/mutable-and-immutable-side-of-python-c2145cf72747 (First result on google).
Thank you for your valuable time, I have just started learning Python. I came across Mutable and Immutable objects.
As far as I know mutable objects can be changed after their creation.
a = [1,2,3]
print(id(a))
45809352
a = [3,2,1]
print(id(a))
52402312
Then why id of the same list "a" gets changed when its values are changed.
your interpretation is incorrect.
When you assign a new list to a, you change its reference.
On the other hand you could do:
a[:] = [3,2,1]
and then the reference would not change.
mutable means that the content of the object is changed. for example a.append(4) actually make a equal to [1, 2, 3, 4], while on the contrary, appending to a string (which is immutable) does not change it, it creates a new one.
However, when you re-assign, you create a new object and assign it to a, you don't alter the existing content of a. The previous content is lost (unless refered-to by some other variable)
If you change a list, its id doesn't change. But you may do things that instead create a new list, and then it will also have a new id.
E.g.,
>>> l=[]
>>> id(l)
140228658969920
>>> l.append(3) # Changes l
>>> l
[3]
>>> id(l)
140228658969920 # Same ID
>>> l = l + [4] # Computes a new list that is the result of l + [4], assigns that
>>> l
[3, 4]
>>> id(l)
140228658977608 # ID changed
When you do
a = [3, 2, 1]
You unlink the list of [1, 2, 3] from variable a.
Create a new list [3, 2, 1] then assign it to a variable.
Being immutable doesn't mean you assign a new object, it means your original object can be changed "in place" for example via .append()
>>> my_list = [1,2,3]
>>> id(my_list)
140532335329544
>>> my_list.append(5)
>>> id(my_list)
140532335329544
>>> my_list[3] = 4
>>> my_list
[1, 2, 3, 4]
>>> id(my_list)
140532335329544
Why is id(a) == id(b) while id(x) != id(y) in the example below:
>>> a = 9
>>> b = 9
>>> id(a)
10901176
>>> id (b)
10901176
>>> id(a) == id(b)
True
>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> id(x) != id(y)
True
>>> id(x)
11428848
>>> id(y)
12943768
From the python 3.6 doc I get for id() "Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value."... But that doesn't explain it to me. Any ideas?
the fact that a and b integers have the same id is just a storage optimization performed by python on immutable objects (which cannot be relied upon, ex: if the numbers are big enough, ids can be different)
Try to change the value of b and you'll see that id(b) changes.
Of course, it's different for lists: cannot benefit from storage optimization since they're mutable: you don't want x to be changed when you change y.
This is a simple question about how Python handles data and variables. I've done a lot of experimenting and have Python mostly figured out, except this keeps tripping me up:
[edit: I separated and rearranged the examples for clarity]
Example 1:
>>> a = [[1], 2]
>>> a[0:1]
[[1]]
>>> a[0:1] = [[5]]
>>> a
[[5], 2] # The assignment worked.
Example 2:
>>> a = [[1], 2]
>>> a[0:1][0]
[1]
>>> a[0:1][0] = [5]
>>> a
[[1], 2] # No change?
Example 3:
>>> a = [[1], 2]
>>> a[0:1][0][0]
1
>>> a[0:1][0][0] = 5
>>> a
[[5], 2] # Why now?
Can anybody explain to me what's going on here?
So far the answers seem to claim that a[0:1] returns a new list containing a reference to the first element of a. But I don't see how that explains Example 1.
a[0:1] is returning a new array which contains a reference to the array [1], thus you end up modifying the inner array via a reference call.
The reason the first case doesn't modify the [1] array is that you're assigning the copied outer array a new inner array value.
Bottom line - a[0:1] returns a copy of the data, but the inner data is not copied.
My understanding is slicing returns a new object. That is it's return value is a new list.
Hence you can not use an assignment operator to changes the values of the original list
>>> a = [[1], 2, 3]
>>> k = a[0:2]
>>> id(a)
4299352904
>>> id(k)
4299353552
>>>
>>> id(a)
4299352904
>>> id(a[0:2])
4299352832
some more plays along the lines
>>> k = 5
>>>
>>> id(k)
4298182344
>>> a[0] = [1,2]
>>> a
[[1, 2], 2, 3]
>>> id(a)
4299352904
>>>
[Edit: on second part of question]
>>> a[0:1] = [[5]]
The following notation is also called commonly as slice assignment
The behavior for builtin lists is atomic (delete + insert) happens in one go. My understanding is that this is not allowed for custom sequence.
There are three distinct operations with indices, all are translated to method calls:
a[i] = b => a.__setitem__(i, b)
del a[i] => a.__delitem__(i)
a[i] used as an expression => a.__getitem__(i)
Here a, b and i are expressions, and i can contain slice objects created using the colon shorthand syntax. E.g.:
>>> class C(object):
... def __setitem__(self, *a):
... print a
...
>>> C()[1] = 0
(1, 0)
>>> C()['foo'] = 0
('foo', 0)
>>> C()['foo':'bar'] = 0
(slice('foo', 'bar', None), 0)
>>> C()['foo':'bar',5] = 0
((slice('foo', 'bar', None), 5), 0)
So what's happening in your third example is this:
a[0:1][0][0] = 5
becomes
a.__getitem__(slice(0,1)).__getitem__(0).__setitem__(0, 5)
The first __getitem__ returns a copy of part of the list, but the second __getitem__ returns the actual list inside that, which is then modified using __setitem__.
Your second example on the other hand becomes
a.__getitem__(slice(0,1)).__setitem__(0, 5)
So __setitem__ is being called on the sliced copy, leaving the original list intact.