Why do variables sometimes bind both directions in Python? [duplicate] - python

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 3 years ago.
Say I have
x = [[0,0]]
y = x[-1]
Then why does
y[1] += 1
give
x = [[0,1]]
y = [0,1]
That is, I'm confused as to why it also changes what x is, even though I only specified something to do with y?

This makes sense if you think of a list as a mutable object in memory and you consider that you're modifying that list.
The variables are simply different names for that same list.
That code is equivalent to:
list_obj = [0, 0]
x = [ list_obj ] # a list with list_obj as
# its single element
y = list_obj # same as x[-1], just
# another name for list_obj
Then it's natural that you're simply modifying list_obj[1] in both cases.

Related

Python .append() method is acting weirdly [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 1 year ago.
list = [[0,0]]
x = [0,0]
for i in range(5):
x[0] += 1
list.append(x)
expected result: [[1,0],[2,0],[3,0],[4,0],[5,0]]
actual result: [[5,0],[5,0],[5,0],[5,0],[5,0]]
I have tried several things, but none seem to work.
I am open to any suggestions, I am trying to keep "x" as a list and would prefer to stay away from doing something like
x1 = x[0]
x2 = x[1]
I think the problem is that it’s appending the list, not its contents, so it changes each time to the current value of the list(x). However, I’m really not sure what the exact problem is.
You could solve your problem by doing the following:
List=[[0,0]]
x=0
for I in range(5):
x += 1
list.append([x,0])

Remove() function in loops and iterations python [duplicate]

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 1 year ago.
vec = [-4,-2,0,2,4]
for x in vec:
if x<0:
print(x)
vec.remove(x)
print(vec)
This is a program to remove negative numbers and retain positive numbers in a list
Without the .remove(x), i printed out -4,-2
But with .remove(x),Why when I print(x), it prints out only -4, and only -4 is removed?
Isn't supposedly -2 will also be printed and removed? Isn't supposedly the vec list finally retains 0,2,4 ?
I have tried putting if x <0 or x==-2 , it doesn't work either instead returning me the same problems
I know I can build a new list like vectwo = [x for x in vec if x>0 or x=0]
but I just can't figured out the logical fallacy in the iteration I built to remove negative numbers.
Dont remove from the list while iterating. It's cleaner to use another list.
vec = [-4,-2,0,2,4]
vec_copy = []
for x in vec:
if x >= 0:
vec_copy.append(x)
print(vec_copy)
You can do this in a single line. But note that you aren't actually removing from numbers from the list, instead you pick the positive items and replace the old list with the new one. It does what you want and it's cleaner this way.
vec = [x for x in vec if x >= 0]

Having problems with assigning variable to each other [duplicate]

This question already has answers here:
Python: if element in one list, change element in other?
(3 answers)
Closed 2 years ago.
I am pretty new to python and I am trying to swap the values of some variables in my code below:
def MutationPop(LocalBestInd,clmns,VNSdata):
import random
MutPop = []
for i in range(0,VNSdata[1]):
tmpMutPop = LocalBestInd
#generation of random numbers
RandomNums = []
while len(RandomNums) < 2:
r = random.randint(0,clmns-1)
if r not in RandomNums:
RandomNums.append(r)
RandomNums = sorted(RandomNums)
#apply swap to berths
tmpMutPop[0][RandomNums[0]] = LocalBestInd[0][RandomNums[1]]
tmpMutPop[0][RandomNums[1]] = LocalBestInd[0][RandomNums[0]]
#generation of random numbers
RandomNums = []
while len(RandomNums) < 2:
r = random.randint(0,clmns-1)
if r not in RandomNums:
RandomNums.append(r)
RandomNums = sorted(RandomNums)
#apply swap to vessels
tmpMutPop[1][RandomNums[0]] = LocalBestInd[1][RandomNums[1]]
tmpMutPop[1][RandomNums[1]] = LocalBestInd[1][RandomNums[0]]
MutPop.append(tmpMutPop)
Neighborhood = MutPop
return(Neighborhood)
my problem is that I do not want to change the variable "LocalBestInd" and want to use it as a reference to generate new "tmpMutPop"s in the loop, but the code put "LocalBestInd" equal to "tmpMutPop" every time that loop is iterated. The same problem happens for other assignments (e.g., tmpMutPop[1][RandomNums[1]] = LocalBestInd[1][RandomNums[0]]) in this code.
Would you please help me to solve this problem?
Thank you
Masoud
Try this:
import copy
And change the line
tmpMutPop = LocalBestInd
to this:
tmpMutPop = copy.copy(LocalBestInd)
Depending on the structure of LocalBestInd, you may need copy.deepcopy() instead.
Here's a quote from the copy documentation that explains what's going on:
Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other.
Assuming that LocalBestInd is a list, the problem, I think, is that when you're setting
tmpMutPop = LocalBestInd
in the loop, the value tmpMutPop is not a separate list but is just a reference to the list LocalBestInd, which actually contains the data. There's only one list - when you try to update the former, you're really only updating the latter.
Simple example of this works here:
>>> x = [1, 2]; y = x; y[0] = 2; print(x)
[2, 2]
What may help you here is calling .copy() on your list, e.g.:
>>> x = [1, 2]; y = x.copy(); y[0] = 2; print(x)
[1, 2]
If that doesn't work then check out the other list copying methods in this SO answer: How to clone or copy a list?

2D array in python changes the whole row when I only want to change 1 item(Is there a way around it?) [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 3 years ago.
I wanted to create a 2D array that would have a number in each cell.
I need to access specific cells and be ablt to change them.
def print_matrix(matrix):
#just to print it nicer
for x in range(0, len(matrix)):
print(matrix[x])
matrix = []
list = []
for x in range(0,10):
list.append(0)
for x in range(0,10):
matrix.append(list)
matrix[1][2] = 9
print_matrix(matrix)
You actually created only one list and added it 10 times to the matrix (by reference).
matrix = []
for x in range(0,10):
row = []
for x in range(0,10):
row.append(0)
matrix.append(row)
Also, it's not advisable to call variables list, for this is a builtin python function.
Use list.copy():
def print_matrix(matrix):
#just to print it nicer
for x in range(0, len(matrix)):
print(matrix[x])
matrix = []
list = []
for x in range(0,10):
list.append(0)
for x in range(0,10):
matrix.append(list.copy())
matrix[1][2] = 9
print_matrix(matrix)
If you don't use copy, matrix simply holds 10 references to the original list. Changing any one of those references simply changes the original list.
When you use .copy(), new lists are created which are copies of the original one, this allows you to change each one independently.
Your problem is that you have list references in each row in your matrix. Check here for a possible solution.

Initialize variables in one line? [duplicate]

This question already has answers here:
Assigning multiple variables in one line
(3 answers)
Closed 8 years ago.
Is it possible do the following initializations in one line? As I am quite curious whether a shorter code is possible.
X = []
Y = []
You can initialize them using sequence unpacking (tuple unpacking in this case)
X, Y = [], []
because it's equivalent to
(X, Y) = ([], [])
You can also use a semicolon to join lines in your example:
X = []; Y = []
You can use tuple unpacking (or multiple assignment):
X, Y = [], []

Categories

Resources