Function change list values, not variable values ​​in Python

Take a simple code:

y = [1,2,3] def plusOne(y): for x in range(len(y)): y[x] += 1 return y print plusOne(y), y a = 2 def plusOne2(a): a += 1 return a print plusOne2(a), a 

The y values ​​change, but the a value remains unchanged. I already learned that this is because it is volatile and the other is not. But how to change the code so that the function does not change the list?

For example, to do something like this (in pseudocode for simplicity):

 a = [1,2,3,...,n] function doSomething(x): do stuff with x return x b = doSomething(a) if someOperation(a) > someOperation(b): do stuff 

EDIT: Sorry, but I have another question about nested lists . See this code:

 def change(y): yN = y[:] for i in range(len(yN)): if yN[i][0] == 1: yN[i][0] = 0 else: yN[i][0] = 1 return yN data1 = [[1],[1],[0],[0]] data2 = change(data1) 

This does not work here. What for? Again: how to avoid this problem? I understand why it does not work: yN = y [:] copies the values ​​of y to yN, but the values ​​are also lists, so the operation must be doubled for each list in the list. How to perform this operation with nested lists?

+5
source share
7 answers

Python variables contain pointers or object references. All values ​​(even integer) are objects, and assignment changes the variable to another object. It does not store the new value in a variable; it changes the variable for reference or points to another object. For this reason, many people say that Python has no "variables", it has "names", and the = operation does not "assign a value to a variable", but rather "binds a name to an object". "

In plusOne you modify (or "mutate") the contents of y , but you never change what relates to y . It remains to point to the same list that you passed to the function. The global variable y and the local variable y belong to the same list, so the changes are visible using any variable. Since you changed the contents of the object that was transferred, there really is no reason to return y (in fact, returning None is what Python does for operations that change the list in place - the values ​​are returned by operations that create new objects rather than mutating existing ones).

In plusOne2 you change the local variable a to refer to another integer object, 3 . ("Binding the name a to object 3 ") The global variable a does not change this and continues to point to 2 .

If you do not want to modify the list that was submitted, make a copy of it and change it. Then your function should return a new list, since this is one of those operations that creates a new object, and the new object will be lost if you do not return it. You can do this as the first line of the function: x = x[:] for example (as others have pointed out). Or, if it would be useful for the function to be called anyway, you can pass the caller to x[:] if he wants to make a copy.

+15
source

Create a copy of the list. Using testList = inputList[:] . See Code

 >>> def plusOne(y): newY = y[:] for x in range(len(newY)): newY[x] += 1 return newY >>> y = [1, 2, 3] >>> print plusOne(y), y [2, 3, 4] [1, 2, 3] 

Or you can create a new list in a function

 >>> def plusOne(y): newList = [] for elem in y: newList.append(elem+1) return newList 

You can also use understanding, as others have pointed out.

 >>> def plusOne(y): return [elem+1 for elem in y] 
+6
source

You can pass a copy of your list using fragment notation:

 print plusOne(y[:]), y 

Or the best way would be to create a copy of the list in the function itself so that the caller does not have to worry about a possible modification:

 def plusOne(y): y_copy = y[:] 

and work with y_copy .


Or, as pointed out by @abarnet comments, you can change the function to use list comprehension , which will generally create a new list:

 return [x + 1 for x in y] 
+4
source

Just create a new list with the values ​​you want in it and return them instead.

 def plus_one(sequence): return [el + 1 for el in sequence] 
+3
source

As others have pointed out, you should use newlist = original[:] or newlist = list(original) to copy the list if you do not want to change the original.

 def plusOne(y): y2 = list(y) # copy the list over, y2 = y[:] also works for i, _ in enumerate(y2): y2[i] += 1 return y2 

However, you can get the desired result with a list comprehension.

 def plusOne(y): return [i+1 for i in y] 

This will lead to navigating the values ​​in y and creating a new list, adding one to each of them

+2
source

To answer the edited question:

Copying nested data structures is called deep copying. To do this in Python, use deepcopy() in copy .

+2
source

You can do this by creating a function and calling this function using the map function, the map function will call the add function and assign a value to it, and then print the new value as follows:

 def add(x): return x+x print(list(map(add,[1,2,3]))) 

Or you can use the function (* range), it is very easy to do, as in this example:

 print ([i+i for i in [*range (1,10)]]) 
+1
source

Source: https://habr.com/ru/post/1491722/


All Articles