Related
I tried to use multiple assignment as show below to initialize variables, but I got confused by the behavior, I expect to reassign the values list separately, I mean b[0] and c[0] equal 0 as before.
a=b=c=[0,3,5]
a[0]=1
print(a)
print(b)
print(c)
Result is:
[1, 3, 5]
[1, 3, 5]
[1, 3, 5]
Is that correct? what should I use for multiple assignment?
what is different from this?
d=e=f=3
e=4
print('f:',f)
print('e:',e)
result:
('f:', 3)
('e:', 4)
If you're coming to Python from a language in the C/Java/etc. family, it may help you to stop thinking about a as a "variable", and start thinking of it as a "name".
a, b, and c aren't different variables with equal values; they're different names for the same identical value. Variables have types, identities, addresses, and all kinds of stuff like that.
Names don't have any of that. Values do, of course, and you can have lots of names for the same value.
If you give Notorious B.I.G. a hot dog,* Biggie Smalls and Chris Wallace have a hot dog. If you change the first element of a to 1, the first elements of b and c are 1.
If you want to know if two names are naming the same object, use the is operator:
>>> a=b=c=[0,3,5]
>>> a is b
True
You then ask:
what is different from this?
d=e=f=3
e=4
print('f:',f)
print('e:',e)
Here, you're rebinding the name e to the value 4. That doesn't affect the names d and f in any way.
In your previous version, you were assigning to a[0], not to a. So, from the point of view of a[0], you're rebinding a[0], but from the point of view of a, you're changing it in-place.
You can use the id function, which gives you some unique number representing the identity of an object, to see exactly which object is which even when is can't help:
>>> a=b=c=[0,3,5]
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261120
>>> id(b[0])
4297261120
>>> a[0] = 1
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261216
>>> id(b[0])
4297261216
Notice that a[0] has changed from 4297261120 to 4297261216—it's now a name for a different value. And b[0] is also now a name for that same new value. That's because a and b are still naming the same object.
Under the covers, a[0]=1 is actually calling a method on the list object. (It's equivalent to a.__setitem__(0, 1).) So, it's not really rebinding anything at all. It's like calling my_object.set_something(1). Sure, likely the object is rebinding an instance attribute in order to implement this method, but that's not what's important; what's important is that you're not assigning anything, you're just mutating the object. And it's the same with a[0]=1.
user570826 asked:
What if we have, a = b = c = 10
That's exactly the same situation as a = b = c = [1, 2, 3]: you have three names for the same value.
But in this case, the value is an int, and ints are immutable. In either case, you can rebind a to a different value (e.g., a = "Now I'm a string!"), but the won't affect the original value, which b and c will still be names for. The difference is that with a list, you can change the value [1, 2, 3] into [1, 2, 3, 4] by doing, e.g., a.append(4); since that's actually changing the value that b and c are names for, b will now b [1, 2, 3, 4]. There's no way to change the value 10 into anything else. 10 is 10 forever, just like Claudia the vampire is 5 forever (at least until she's replaced by Kirsten Dunst).
* Warning: Do not give Notorious B.I.G. a hot dog. Gangsta rap zombies should never be fed after midnight.
Cough cough
>>> a,b,c = (1,2,3)
>>> a
1
>>> b
2
>>> c
3
>>> a,b,c = ({'test':'a'},{'test':'b'},{'test':'c'})
>>> a
{'test': 'a'}
>>> b
{'test': 'b'}
>>> c
{'test': 'c'}
>>>
In python, everything is an object, also "simple" variables types (int, float, etc..).
When you changes a variable value, you actually changes it's pointer, and if you compares between two variables it's compares their pointers.
(To be clear, pointer is the address in physical computer memory where a variable is stored).
As a result, when you changes an inner variable value, you changes it's value in the memory and it's affects all the variables that point to this address.
For your example, when you do:
a = b = 5
This means that a and b points to the same address in memory that contains the value 5, but when you do:
a = 6
It's not affect b because a is now points to another memory location that contains 6 and b still points to the memory address that contains 5.
But, when you do:
a = b = [1,2,3]
a and b, again, points to the same location but the difference is that if you change the one of the list values:
a[0] = 2
It's changes the value of the memory that a is points on, but a is still points to the same address as b, and as a result, b changes as well.
Yes, that's the expected behavior. a, b and c are all set as labels for the same list. If you want three different lists, you need to assign them individually. You can either repeat the explicit list, or use one of the numerous ways to copy a list:
b = a[:] # this does a shallow copy, which is good enough for this case
import copy
c = copy.deepcopy(a) # this does a deep copy, which matters if the list contains mutable objects
Assignment statements in Python do not copy objects - they bind the name to an object, and an object can have as many labels as you set. In your first edit, changing a[0], you're updating one element of the single list that a, b, and c all refer to. In your second, changing e, you're switching e to be a label for a different object (4 instead of 3).
You can use id(name) to check if two names represent the same object:
>>> a = b = c = [0, 3, 5]
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488
Lists are mutable; it means you can change the value in place without creating a new object. However, it depends on how you change the value:
>>> a[0] = 1
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488
>>> print(a, b, c)
[1, 3, 5] [1, 3, 5] [1, 3, 5]
If you assign a new list to a, then its id will change, so it won't affect b and c's values:
>>> a = [1, 8, 5]
>>> print(id(a), id(b), id(c))
139423880 46268488 46268488
>>> print(a, b, c)
[1, 8, 5] [1, 3, 5] [1, 3, 5]
Integers are immutable, so you cannot change the value without creating a new object:
>>> x = y = z = 1
>>> print(id(x), id(y), id(z))
507081216 507081216 507081216
>>> x = 2
>>> print(id(x), id(y), id(z))
507081248 507081216 507081216
>>> print(x, y, z)
2 1 1
in your first example a = b = c = [1, 2, 3] you are really saying:
'a' is the same as 'b', is the same as 'c' and they are all [1, 2, 3]
If you want to set 'a' equal to 1, 'b' equal to '2' and 'c' equal to 3, try this:
a, b, c = [1, 2, 3]
print(a)
--> 1
print(b)
--> 2
print(c)
--> 3
Hope this helps!
What you need is this:
a, b, c = [0,3,5] # Unpack the list, now a, b, and c are ints
a = 1 # `a` did equal 0, not [0,3,5]
print(a)
print(b)
print(c)
Simply put, in the first case, you are assigning multiple names to a list. Only one copy of list is created in memory and all names refer to that location. So changing the list using any of the names will actually modify the list in memory.
In the second case, multiple copies of same value are created in memory. So each copy is independent of one another.
The code that does what I need could be this:
# test
aux=[[0 for n in range(3)] for i in range(4)]
print('aux:',aux)
# initialization
a,b,c,d=[[0 for n in range(3)] for i in range(4)]
# changing values
a[0]=1
d[2]=5
print('a:',a)
print('b:',b)
print('c:',c)
print('d:',d)
Result:
('aux:', [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]])
('a:', [1, 0, 0])
('b:', [0, 0, 0])
('c:', [0, 0, 0])
('d:', [0, 0, 5])
To assign multiple variables same value I prefer list
a, b, c = [10]*3#multiplying 3 because we have 3 variables
print(a, type(a), b, type(b), c, type(c))
output:
10 <class 'int'> 10 <class 'int'> 10 <class 'int'>
Initialize multiple objects:
import datetime
time1, time2, time3 = [datetime.datetime.now()]*3
print(time1)
print(time2)
print(time3)
output:
2022-02-25 11:52:59.064487
2022-02-25 11:52:59.064487
2022-02-25 11:52:59.064487
E.g: basically a = b = 10 means both a and b are pointing to 10 in the memory, you can test by id(a) and id(b) which comes out exactly equal to a is b as True.
is matches the memory location but not its value, however == matches the value.
let's suppose, you want to update the value of a from 10 to 5, since the memory location was pointing to the same memory location you will experience the value of b will also be pointing to 5 because of the initial declaration.
The conclusion is to use this only if you know the consequences otherwise simply use , separated assignment like a, b = 10, 10 and won't face the above-explained consequences on updating any of the values because of different memory locations.
The behavior is correct. However, all the variables will share the same reference. Please note the behavior below:
>>> a = b = c = [0,1,2]
>>> a
[0, 1, 2]
>>> b
[0, 1, 2]
>>> c
[0, 1, 2]
>>> a[0]=1000
>>> a
[1000, 1, 2]
>>> b
[1000, 1, 2]
>>> c
[1000, 1, 2]
So, yes, it is different in the sense that if you assign a, b and c differently on a separate line, changing one will not change the others.
Here are two codes for you to choose one:
a = b = c = [0, 3, 5]
a = [1, 3, 5]
print(a)
print(b)
print(c)
or
a = b = c = [0, 3, 5]
a = [1] + a[1:]
print(a)
print(b)
print(c)
Let's say I have:
a=[1,2,3]
b=[4,5,6]
Now I want to create a list of list from a and b, I would do it like this:
c=[a,b]=[[1,2,3],[4,5,6]]
As a.append(b) would result in: [1,2,3,b]=[1,2,3,[4,5,6]]
Now let's say there exists anew list which I want to append to c:
d=[7,8,9]
I now have to do c.append(d) to get [[1,2,3],[4,5,6],[7,8,9]]
Because
e=[c,d]=[[[1,2,3],[4,5,6]],[7,8,9]]
How can I get a list of list from individual lists without know how my lists are structured?
Try this:
a = [1,2,3]
b = [4,5,6]
c = []
c.append(a)
c.append(b)
This should work, and only takes 2 simple lines.
The two actions you are describing are distinctly different. The first is creating the outer list (a.k.a. c) and the second is appending to it.
To make the process more uniform you can just start off with an outer list and append all the child lists to it.
c = []
a=[1,2,3]
b=[4,5,6]
d=[7,8,9]
c.append(a)
c.append(b)
c.append(d)
c is now
[[[1,2,3],[4,5,6]],[7,8,9]]
A bit roundabout of a way but looks nice, using numpy
a = np.array([[1,2,3]])
b = np.array([[4,5,6]])
c = np.append(a,b,axis=0)
print(c.tolist())
gives you
[[1,2,3],[4,5,6]]
Appending another list in the same way keeps the structure of list of lists, for example
d = np.array([[7,8,9]])
e = np.append(c,d,axis=0)
print(e.tolist())
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Now this is quite roundabout. I would just keep everything in numpy arrays if possible.
EDIT: Figured out how to do this without numpy
Simply state each list as a list of lists to begin with
a = [[1,2,3]]
b = [[4,5,6]]
a.extend(b)
print(a)
[[1,2,3],[4,5,6]]
Furthermore you can do this
d = [[7,8,9]]
a.extend(d)
print(a)
[[1, 2, 3], [4, 5, 6], [4, 5, 6]]
pset = []
def powe(a):
powehelp(a,0)
def powehelp(a, ind):
if len(a) == ind:
pset.append(a)
return
powehelp(a[:], ind+1)
a.pop(ind)
powehelp(a[:],ind)
powe([1,2,3])
print(pset)
This code creates its subset, and in this code I want to know why I can't use powehelp(a, ind+1) instead of powehelp(a[:], ind+1)?
I know that a[:] means get all the values of list a.
When using a, the result is [[], [], [], []].
Your powehelp function uses pop, which means it alters the list it is given.
If you pass a into it, it is a that gets altered, and evidently ends up empty.
a[:] creates a copy of a. If you pass a[:] into powehelp, your original list a is unaffected.
The given a is a list in itself, and so appending a list to a list would make a nested list.
a = [1, 2, 3]
b = []
b.append(a)
b
[[1, 2, 3]]
When you pset.append(a) you insert the list a into the endtail of the list pset so you result is a nested list. If I understand your requirement correctly, you're looking to concatenate your lists, as in:
c = [4, 5, 6]
a + c
[1, 2, 3, 4, 5, 6]
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.
I have a function that generates all permutations of a string. It prints out all the possible permutations just fine. But now I want a list of all such permutations.
I tried making the global list as well as tried passing it as a parameter, but post appending the permutation all the lists previously in the main list get changed to the list last appended. Please explain this behavior
def permutationNum(a,lower,upper,perm):
if(lower==upper):
print(a)
print(perm)
perm.append(a)
# perm = perm.append(a)
else:
for i in range(lower,upper+1):
a[lower],a[i] = a[i],a[lower]
permutationNum(a,lower+1,upper, perm)
a[lower],a[i] = a[i],a[lower]
listy = [1,2,3]
perm = []
permutationNum(listy, 0, len(listy)-1, perm)
print(perm)
Output : [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
Expected Output : [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 2, 1], [3, 1, 2]]
UPDATE:
Turns out it was indeed deep copy problem after all. I just had a temp variable store a deep copy of a and appended that temp variable to the list. It all worked out.
In python, certain data types are copied when passed into functions as arguments, while others are referenced.
If an argument is copied, any changes to it inside the function will not affect the original variable that was passed in.
If an argument is referenced, any changes to it inside the function will affect the original.
Strings, Ints, Floats are copied, while objects and lists are referenced. This behaviour is also replicated when assigning one variable to another:
a = 5
b = a
b = 6
print(a)
>>> 5
a = [5]
b = a
b.append(6)
print(a)
>>> [5, 6]
If you want to copy a list and not just reference it, there's multiple ways you can achieve this:
Copy Module
import copy
a = [5]
b = copy.copy(a)
b.append(6)
print(a)
>>> [5]
Slicing
a = [5]
b = a[:]
b.append(6)
print(a)
>>> [5]
.copy()
a = [5]
b = a.copy()
b.append(6)
print(a)
>>> [5]
list()
a = [5]
b = list(a)
b.append(6)
print(a)
>>> [5]
So in your case, you would change the following line from:
permutationNum(a,lower+1,upper, perm) to
permutationNum(a[:],lower+1,upper, perm)
Change this line - to append new instance of list everytime
perm.append(list(a))
Another way to get permutations:
import itertools
def permutationNum(a):
for x in itertools.permutations(a):
perm.append(list(x))
listy = [1,2,3]
perm = []
permutationNum(listy)
print(perm)
or
import itertools
def permutationNum(a):
return [list(x) for x in itertools.permutations(a)]
listy = [1,2,3]
print(permutationNum(listy))
Given that in Python:
element = element + [0]
should be equal to:
element += [0]
Why does one modify a list and the other does not? Here is a example:
>>> a = [[0, 0], [0,0]]
>>> for element in a:
... element = element + [0]
...
>>> a
[[0, 0], [0, 0]]
a is not modified. But if I increment:
>>> a = [[0, 0], [0,0]]
>>> for element in a:
... element += [0]
...
>>> a
[[0, 0, 0], [0, 0, 0]]
a is modified.
Thanks,
Frank
This is a fun side-effect of += operatior, which calls __iadd__ instead of __add__.
The statement x = x + y is equivalent to x = x.__add__(y), while x += y is equivalent to x = x.__iadd__(y).
This lets the list class optimize += by extending the existing (ex, x += y is roughly equivalent to x.extend(y)) list instead of creating an entirely new list (which is what + needs to do).
For example:
>>> a = [1, 2, 3]
>>> original_a = a
>>> b = [1, 2, 3]
>>> original_b = b
>>> a += [4]
>>> b = b + [4]
>>> a is original_a
True
>>> b is original_b
False
You can see that using += maintains the identity of the left hand side (ie, a new list isn't created) while using + does not maintain the identity (ie, a new list is created).
For more, see: http://docs.python.org/library/operator.html#operator.iadd and the paragraph directly above the documentation for operator.iadd.
In the first case, element = element + [0], you are creating a new list.
In the second case, element += [0], you are modifying an existing list.
Since the list of lists, a, contains pointers to the elements, only modifying the elements will actually change things. (That is, creating a new list does not change the pointers in a.)
This is seen more clearly if we take a simple example showing how lists work:
>>> a = [1, 2, 3]
>>> b = a
>>> a = [4, 5, 6]
>>> a
[4, 5, 6]
>>> b
[1, 2, 3]
>>> a = [1, 2, 3]
>>> b = a
>>> a += [4, 5, 6]
>>> b
[1, 2, 3, 4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
Assigning a variable to a list simply assigns a pointer.
Adding to what others said, there is a difference in what these statements do:
element = element + [0]
does
element = element.__add__([0])
while
element += [0]
does
element = element.__iadd__([0])
__iadd__(), in this case, is free to determine what to return: the original object with a modification or a new object.
In the case of a immutable object, it must return a different one (e.g., a = b = 8; a += 9 => a is not b.
But in the case of a mutable object, such as a list, it normally modifies this one:
a = b = []
a += [8]
=> a is b.
This different behaviour reflects in your for loop:
for element in a:
element = element + [0]
=> name element gets rebound to a different object; original one remains untouched
for element in a:
element += [0]
=> original object, which is as well contained in the outer list, a, gets modified. The fact that element is reassigned is irrelevant; it is not used.