I know list is a kind of changeable collection of data object ,but why the output is different.
I thought they should be the same.
a = [1]
b = a
b = [1,2]
print(a)
output:
[1]
a = [1]
b = a
b.append(2)
print(a)
output:
[1,2]
In the first example you are overwriting:
a=[1]
b=a # b=[1] and b=a
b=[1,2] # b=[1,2] but not a
in the second example you apply a function built into lists:
a=[1]
b=a # b=[1] and b=a
b.append(1) # applies append to b which is a so a.append is done
a = [1]
b = a
b = [1,2]
print(a)
When you do this, the value for b is reassigned therefore losing the connection with a.
a = [1]
b = a
b.append(2)
print(a)
But here, appending to b means the same list in the memory is appended a value. Since a and b still refer to the same memory, printing a results the same as b since they two are just two different aliases for the list.
Related
When using python, as the code shows, when we run the 'print(a)' inside the function. The result is [2,1,3]. However, why the list b is [[1,2,3]] but c is [[2,1,3]].
What's more, if we delete the last sentence of the function (as shown in second part of code), it works well again. It seems .append() runs after the function finishes, why??
a = [1,2,3]
b = []
c = []
def function():
a[0], a[1] = a[1], a[0]
print(a)
b.append(a)
c.append(a[:])
a[0], a[1] = a[1], a[0]
function()
print(a)
print(b)
print(c)
[2,1,3]
[1,2,3]
[[1,2,3]]
[[2,1,3]]
a = [1,2,3]
b = []
c = []
def function():
a[0], a[1] = a[1], a[0]
print(a)
b.append(a)
c.append(a[:])
function()
print(a)
print(b)
print(c)
[2,1,3]
[2,1,3]
[[2,1,3]]
[[2,1,3]]
It seems that
b.append(a)
appends the variable a and
c.append(a[:])
appends the contents of a. In the first case, the variable is appended so a change in the variable a changes the value of b since the variable a is appended. In the second case, you are just appending a's contents and not the variable. The first is like saying:
b = [a]
and the second is like saying:
c = [2,1,3]
In Python, lists are passed by reference to functions, right?
If that is so, what's happening here?
>>> def f(a):
... print(a)
... a = a[:2]
... print(a)
...
>>> b = [1,2,3]
>>> f(b)
[1, 2, 3]
[1, 2]
>>> print(b)
[1, 2, 3]
>>>
In the statement:
a = a[:2]
you are creating a new local (to f()) variable which you call using the same name as the input argument a.
That is, what you are doing is equivalent to:
def f(a):
print(a)
b = a[:2]
print(b)
Instead, you should be changing a in place such as:
def f(a):
print(a)
a[:] = a[:2]
print(a)
When you do:
a = a[:2]
it reassigns a to a new value (The first two items of the list).
All Python arguments are passed by reference. You need to change the object that it is refered to, instead of making a refer to a new object.
a[2:] = []
# or
del a[2:]
# or
a[:] = a[:2]
Where the first and last assign to slices of the list, changing the list in-place (affecting its value), and the middle one also changes the value of the list, by deleting the rest of the elements.
Indeed the objects are passed by reference but a = a[:2] basically creates a new local variable that points to slice of the list.
To modify the list object in place you can assign it to its slice(slice assignment).
Consider a and b here equivalent to your global b and local a, here assigning a to new object doesn't affect b:
>>> a = b = [1, 2, 3]
>>> a = a[:2] # The identifier `a` now points to a new object, nothing changes for `b`.
>>> a, b
([1, 2], [1, 2, 3])
>>> id(a), id(b)
(4370921480, 4369473992) # `a` now points to a different object
Slice assignment work as expected:
>>> a = b = [1, 2, 3]
>>> a[:] = a[:2] # Updates the object in-place, hence affects all references.
>>> a, b
([1, 2], [1, 2])
>>> id(a), id(b)
(4370940488, 4370940488) # Both still point to the same object
Related: What is the difference between slice assignment that slices the whole list and direct assignment?
I'm trying to generate a list of permutations (also lists) by appending a global list as each permutation is generated. I can tell the permutations are being generated properly by printing each after it is generated. However, after the function is called my global list only contains the original list for each time a permutation was generated by the function.
array = []
def perms(a, k):
if (k == len(a)):
global array
array.append(a)
print(a) #perms function is working properly
else:
for i in range(k, len(a)):
a[k], a[i] = a[i], a[k]
perms(a, k+1)
a[k], a[i] = a[i], a[k]
perms([1,2,3,4], 0)
#only prints the original list for each time a perm was generated
for i in array: print(i)
When I am printing at the bottom it is showing array = [[1,2,3,4], [1,2,3,4], ...]
It seems like my global list array can only see the perms parameter a in the scope it was called in.
How would this be done properly?
In Python, lists are mutable. So when you call perms(a, k+1) inside perms, you're ending up with the exact same instance of a inside the recursive call. Consider this example:
>>> a = []
>>> b = [4,5,6]
>>> a.append(b)
>>> print a
[[4, 5, 6]]
>>> b.append(7)
>>> print a
[[4, 5, 6, 7]]
As you can see, editing the b list directly also edits the b that was appended to the a list, because both b and a[0] are referencing the exact same object:
>>> b is a[0]
True
You don't see this behavior with strings, which are immutable:
>>> a = []
>>> b = "hi"
>>> a.append(b)
>>> print a
['hi']
>>> b = "blah"
>>> print a
['hi']
>>> b is a[0]
False
You can fix the issue in your code by passing a copy of the a list into the recursive call, like this:
perms(a[:], k+1)
In Perl I can say this :
> perl -e '#a=(1,2,3);$b=\#a;$$b[1]=5;print #a'
153
#a=(1,2,3);
$b=\#a;
$$b[1]=5;
print #a
i.e. I can change the original variable #a via the reference $b.
How can I do that in Python ?
=========
Sorry my mistake I was trying to delete the content of the referent array "a" via the reference "b".. and it does not seem to work.
What is the correct way to delete a via b
> a = [1,2,3]
> b = a
> b
[1, 2, 3]
> b = []
> a
[1, 2, 3]
'a' still not empty i.e. I have reference to variable and I want to clean it up via the reference?
All types in Python are references. That means you cannot re-assign an actual variable and expect it to change the original variable. However, you can certainly modify a variable through a "reference" which is automatically created on copy.
a = [1,2,3]
b = a
b[0] = 0
print a
Output
[0,2,3]
If you want to delete a list via a reference, you can use the other solution or do the following:
b[:] = []
You can mutate a list via deletion as such:
>>> a = [1, 2, 3]
>>> b = a
>>> del b[:]
>>> b
[]
>>> a
[]
The special syntax del b[:] is equivalent to b.__delitem__(slice(0, len(b))) - that is, it calls a method on the object that b points to, which ends up mutating that object, instead of assigning a different object to b which is what b = [] does.
I can't find concise information about what is going on in this very simple program:
print 'case 1'
# a and b stay different
a = [1,2,3]
b = a
b = [4,5,6]
print 'a =',a
print 'b =',b
print
print 'case 2'
# a and b becomes equal
a = [1,2,3]
b = a
b[0] = 4
b[1] = 5
b[2] = 6
print 'a =',a
print 'b =',b
print
print 'case 3'
# a and b stay different now
a = [1,2,3]
b = a[:]
b[0] = 4
b[1] = 5
b[2] = 6
print 'a =',a
print 'b =',b
print
print 'case 4'
# now the funny thing
a=[1,2,[3]]
b=a[:]
b[0] = 4
b[1] = 5
b[2][0] = 6 # this modifies b and a!!!
The output of this simple test is:
case 1
a = [1, 2, 3]
b = [4, 5, 6]
case 2
a = [4, 5, 6]
b = [4, 5, 6]
case 3
a = [1, 2, 3]
b = [4, 5, 6]
case 4
a = [1, 2, [6]]
b = [4, 5, [6]]
I clearly do not understand how python handles each case. Could any one provide a link so that I can read about it, or a short explanation of what is happening?
Thanks a lot.
This is a fantastic visualization tool for python code.
Run your code in it and everything should become clear in a minute.
There are two important things here:
Variables are just labels pointing to objects
List are mutable in python and integers aren't.
When you find that both a and b are modified, then that's because both of them are pointing to the same object. You can do id(a) and id(b) to confirm this.
Regarding the examples, note that a[:] will create a new object which is a copy of a. However, it will be a shallow copy, not a deep copy. This explains why in example 4, you can still modify both a and b. They are pointing to different list objects, but one element is another list that is shared by both of them.
Case 1: The name b is rebound.
Case 2: a and b are bound to the same object.
Case 3: A shallow copy of a is bound to b. The lists are different, but the objects within the list are the same.
Case 4: A shallow copy of a is bound to b, and then one of the objects is mutated.
Rebinding does not mutate, and mutation does not rebind.
print 'case 1'
# a and b stay different
a = [1,2,3]
b = a #At this point 'b' and 'a' are the same,
#just names given to the list
b = [4,5,6] #At this point you assign the name 'b' to a different list
print 'a =',a
print 'b =',b
print
print 'case 2'
# a and b becomes equal
a = [1,2,3] #At this point 'b' and 'a' are the same,
#just names given to the list
b = a
b[0] = 4 #From here you modify the list, since both 'a' and 'b'
#reference the same list, you will see the change in 'a'
b[1] = 5
b[2] = 6
print 'case 3'
# a and b stay different now
a = [1,2,3]
b = a[:] #At this point you COPY the elements from 'a' into a new
#list that is referenced by 'b'
b[0] = 4 #From here you modify 'b' but this has no connection to 'a'
b[1] = 5
b[2] = 6
print 'a =',a
print 'b =',b
print
print 'case 4'
# now the funny thing
a=[1,2,[3]]
b=a[:] #At this point you COPY the elements from 'a' into a new
#list that is referenced by 'b'
b[0] = 4 #Same as before
b[1] = 5
b[2][0] = 6 # this modifies b and a!!! #Here what happens is that 'b[2]' holds
#the same list as 'a[2]'. Since you only modify the element of that
#list that will be visible in 'a', try to see it as cases 1/2 just
#'recursively'. If you do b[2] = 0, that won't change 'a'