Class function is changed global variables - python

I = [[140,50],[140,80],[140,110],[140,140]]
O = [[140,50],[170,50],[140,80],[170,80]]
tomato = [I,O]
class Change():
def __init__(self,):
self.liste = []
def change(self,):
self.liste.extend(tomato[0])
for i in range(10):
self.liste[0][0] += 10
That class when ı use change method this changing global tomato[0] how can i fix that.

Here is a simplified example illustrating your problem.
Initialize a list object x:
x = [0]
Initialize another list a, storing the previous list x in it as an element:
a = [x]
Initialize yet another list b and add the elements from a to it;
the only element in a is the list object x, which is now appended to b:
b = []
b.extend(a)
This means that the first (and only) element in b is that same list object x;
not a clone, not another list with its elements, but that exact same object:
print(b[0] is x)
Gives True.
Notice that I did not check equality, but identity using is.
This means I can write
b[0][0] = 1
print(x[0] == 1)
and get True.
Your code is a great example of why it is usually a terrible idea to muck around with global variables.

Related

Learning python: Why these two function yield different results? [duplicate]

I'm trying to understand Python's approach to variable scope. In this example, why is f() able to alter the value of x, as perceived within main(), but not the value of n?
def f(n, x):
n = 2
x.append(4)
print('In f():', n, x)
def main():
n = 1
x = [0,1,2,3]
print('Before:', n, x)
f(n, x)
print('After: ', n, x)
main()
Output:
Before: 1 [0, 1, 2, 3]
In f(): 2 [0, 1, 2, 3, 4]
After: 1 [0, 1, 2, 3, 4]
See also: How do I pass a variable by reference?
Some answers contain the word "copy" in the context of a function call. I find it confusing.
Python doesn't copy objects you pass during a function call ever.
Function parameters are names. When you call a function, Python binds these parameters to whatever objects you pass (via names in a caller scope).
Objects can be mutable (like lists) or immutable (like integers and strings in Python). A mutable object you can change. You can't change a name, you just can bind it to another object.
Your example is not about scopes or namespaces, it is about naming and binding and mutability of an object in Python.
def f(n, x): # these `n`, `x` have nothing to do with `n` and `x` from main()
n = 2 # put `n` label on `2` balloon
x.append(4) # call `append` method of whatever object `x` is referring to.
print('In f():', n, x)
x = [] # put `x` label on `[]` ballon
# x = [] has no effect on the original list that is passed into the function
Here are nice pictures on the difference between variables in other languages and names in Python.
You've got a number of answers already, and I broadly agree with J.F. Sebastian, but you might find this useful as a shortcut:
Any time you see varname =, you're creating a new name binding within the function's scope. Whatever value varname was bound to before is lost within this scope.
Any time you see varname.foo() you're calling a method on varname. The method may alter varname (e.g. list.append). varname (or, rather, the object that varname names) may exist in more than one scope, and since it's the same object, any changes will be visible in all scopes.
[note that the global keyword creates an exception to the first case]
f doesn't actually alter the value of x (which is always the same reference to an instance of a list). Rather, it alters the contents of this list.
In both cases, a copy of a reference is passed to the function. Inside the function,
n gets assigned a new value. Only the reference inside the function is modified, not the one outside it.
x does not get assigned a new value: neither the reference inside nor outside the function are modified. Instead, x’s value is modified.
Since both the x inside the function and outside it refer to the same value, both see the modification. By contrast, the n inside the function and outside it refer to different values after n was reassigned inside the function.
I will rename variables to reduce confusion. n -> nf or nmain. x -> xf or xmain:
def f(nf, xf):
nf = 2
xf.append(4)
print 'In f():', nf, xf
def main():
nmain = 1
xmain = [0,1,2,3]
print 'Before:', nmain, xmain
f(nmain, xmain)
print 'After: ', nmain, xmain
main()
When you call the function f, the Python runtime makes a copy of xmain and assigns it to xf, and similarly assigns a copy of nmain to nf.
In the case of n, the value that is copied is 1.
In the case of x the value that is copied is not the literal list [0, 1, 2, 3]. It is a reference to that list. xf and xmain are pointing at the same list, so when you modify xf you are also modifying xmain.
If, however, you were to write something like:
xf = ["foo", "bar"]
xf.append(4)
you would find that xmain has not changed. This is because, in the line xf = ["foo", "bar"] you have change xf to point to a new list. Any changes you make to this new list will have no effects on the list that xmain still points to.
Hope that helps. :-)
If the functions are re-written with completely different variables and we call id on them, it then illustrates the point well. I didn't get this at first and read jfs' post with the great explanation, so I tried to understand/convince myself:
def f(y, z):
y = 2
z.append(4)
print ('In f(): ', id(y), id(z))
def main():
n = 1
x = [0,1,2,3]
print ('Before in main:', n, x,id(n),id(x))
f(n, x)
print ('After in main:', n, x,id(n),id(x))
main()
Before in main: 1 [0, 1, 2, 3] 94635800628352 139808499830024
In f(): 94635800628384 139808499830024
After in main: 1 [0, 1, 2, 3, 4] 94635800628352 139808499830024
z and x have the same id. Just different tags for the same underlying structure as the article says.
My general understanding is that any object variable (such as a list or a dict, among others) can be modified through its functions. What I believe you are not able to do is reassign the parameter - i.e., assign it by reference within a callable function.
That is consistent with many other languages.
Run the following short script to see how it works:
def func1(x, l1):
x = 5
l1.append("nonsense")
y = 10
list1 = ["meaning"]
func1(y, list1)
print(y)
print(list1)
It´s because a list is a mutable object. You´re not setting x to the value of [0,1,2,3], you´re defining a label to the object [0,1,2,3].
You should declare your function f() like this:
def f(n, x=None):
if x is None:
x = []
...
n is an int (immutable), and a copy is passed to the function, so in the function you are changing the copy.
X is a list (mutable), and a copy of the pointer is passed o the function so x.append(4) changes the contents of the list. However, you you said x = [0,1,2,3,4] in your function, you would not change the contents of x in main().
Python is copy by value of reference. An object occupies a field in memory, and a reference is associated with that object, but itself occupies a field in memory. And name/value is associated with a reference. In python function, it always copy the value of the reference, so in your code, n is copied to be a new name, when you assign that, it has a new space in caller stack. But for the list, the name also got copied, but it refer to the same memory(since you never assign the list a new value). That is a magic in python!
When you are passing the command n = 2 inside the function, it finds a memory space and label it as 2. But if you call the method append, you are basically refrencing to location x (whatever the value is) and do some operation on that.
Python is a pure pass-by-value language if you think about it the right way. A python variable stores the location of an object in memory. The Python variable does not store the object itself. When you pass a variable to a function, you are passing a copy of the address of the object being pointed to by the variable.
Contrast these two functions
def foo(x):
x[0] = 5
def goo(x):
x = []
Now, when you type into the shell
>>> cow = [3,4,5]
>>> foo(cow)
>>> cow
[5,4,5]
Compare this to goo.
>>> cow = [3,4,5]
>>> goo(cow)
>>> goo
[3,4,5]
In the first case, we pass a copy the address of cow to foo and foo modified the state of the object residing there. The object gets modified.
In the second case you pass a copy of the address of cow to goo. Then goo proceeds to change that copy. Effect: none.
I call this the pink house principle. If you make a copy of your address and tell a
painter to paint the house at that address pink, you will wind up with a pink house.
If you give the painter a copy of your address and tell him to change it to a new address,
the address of your house does not change.
The explanation eliminates a lot of confusion. Python passes the addresses variables store by value.
As jouell said. It's a matter of what points to what and i'd add that it's also a matter of the difference between what = does and what the .append method does.
When you define n and x in main, you tell them to point at 2 objects, namely 1 and [1,2,3]. That is what = does : it tells what your variable should point to.
When you call the function f(n,x), you tell two new local variables nf and xf to point at the same two objects as n and x.
When you use "something"="anything_new", you change what "something" points to. When you use .append, you change the object itself.
Somehow, even though you gave them the same names, n in the main() and the n in f() are not the same entity, they only originally point to the same object (same goes for x actually). A change to what one of them points to won't affect the other. However, if you instead make a change to the object itself, that will affect both variables as they both point to this same, now modified, object.
Lets illustrate the difference between the method .append and the = without defining a new function :
compare
m = [1,2,3]
n = m # this tells n to point at the same object as m does at the moment
m = [1,2,3,4] # writing m = m + [4] would also do the same
print('n = ', n,'m = ',m)
to
m = [1,2,3]
n = m
m.append(4)
print('n = ', n,'m = ',m)
In the first code, it will print n = [1, 2, 3] m = [1, 2, 3, 4], since in the 3rd line, you didnt change the object [1,2,3], but rather you told m to point to a new, different, object (using '='), while n still pointed at the original object.
In the second code, it will print n = [1, 2, 3, 4] m = [1, 2, 3, 4]. This is because here both m and n still point to the same object throughout the code, but you modified the object itself (that m is pointing to) using the .append method... Note that the result of the second code will be the same regardless of wether you write m.append(4) or n.append(4) on the 3rd line.
Once you understand that, the only confusion that remains is really to understand that, as I said, the n and x inside your f() function and the ones in your main() are NOT the same, they only initially point to the same object when you call f().
Please allow me to edit again. These concepts are my experience from learning python by try error and internet, mostly stackoverflow. There are mistakes and there are helps.
Python variables use references, I think reference as relation links from name, memory adress and value.
When we do B = A, we actually create a nickname of A, and now the A has 2 names, A and B. When we call B, we actually are calling the A. we create a ink to the value of other variable, instead of create a new same value, this is what we call reference. And this thought would lead to 2 porblems.
when we do
A = [1]
B = A # Now B is an alias of A
A.append(2) # Now the value of A had been changes
print(B)
>>> [1, 2]
# B is still an alias of A
# Which means when we call B, the real name we are calling is A
# When we do something to B, the real name of our object is A
B.append(3)
print(A)
>>> [1, 2, 3]
This is what happens when we pass arguments to functions
def test(B):
print('My name is B')
print(f'My value is {B}')
print(' I am just a nickname, My real name is A')
B.append(2)
A = [1]
test(A)
print(A)
>>> [1, 2]
We pass A as an argument of a function, but the name of this argument in that function is B.
Same one with different names.
So when we do B.append, we are doing A.append
When we pass an argument to a function, we are not passing a variable , we are passing an alias.
And here comes the 2 problems.
the equal sign always creates a new name
A = [1]
B = A
B.append(2)
A = A[0] # Now the A is a brand new name, and has nothing todo with the old A from now on.
B.append(3)
print(A)
>>> 1
# the relation of A and B is removed when we assign the name A to something else
# Now B is a independent variable of hisown.
the Equal sign is a statesment of clear brand new name,
this was the concused part of mine
A = [1, 2, 3]
# No equal sign, we are working on the origial object,
A.append(4)
>>> [1, 2, 3, 4]
# This would create a new A
A = A + [4]
>>> [1, 2, 3, 4]
and the function
def test(B):
B = [1, 2, 3] # B is a new name now, not an alias of A anymore
B.append(4) # so this operation won't effect A
A = [1, 2, 3]
test(A)
print(A)
>>> [1, 2, 3]
# ---------------------------
def test(B):
B.append(4) # B is a nickname of A, we are doing A
A = [1, 2, 3]
test(A)
print(A)
>>> [1, 2, 3, 4]
the first problem is
the left side of and equation is always a brand new name, new variable,
unless the right side is a name, like B = A, this create an alias only
The second problem, there are something would never be changed, we cannot modify the original, can only create a new one.
This is what we call immutable.
When we do A= 123 , we create a dict which contains name, value, and adress.
When we do B = A, we copy the adress and value from A to B, all operation to B effect the same adress of the value of A.
When it comes to string, numbers, and tuple. the pair of value and adress could never be change. When we put a str to some adress, it was locked right away, the result of all modifications would be put into other adress.
A = 'string' would create a protected value and adess to storage the string 'string' . Currently, there is no built-in functions or method cound modify a string with the syntax like list.append, because this code modify the original value of a adress.
the value and adress of a string, a number, or a tuple is protected, locked, immutable.
All we can work on a string is by the syntax of A = B.method , we have to create a new name to storage the new string value.
please extend this discussion if you still get confused.
this discussion help me to figure out mutable / immutable / refetence / argument / variable / name once for all, hopely this could do some help to someone too.
##############################
had modified my answer tons of times and realized i don't have to say anything, python had explained itself already.
a = 'string'
a.replace('t', '_')
print(a)
>>> 'string'
a = a.replace('t', '_')
print(a)
>>> 's_ring'
b = 100
b + 1
print(b)
>>> 100
b = b + 1
print(b)
>>> 101
def test_id(arg):
c = id(arg)
arg = 123
d = id(arg)
return
a = 'test ids'
b = id(a)
test_id(a)
e = id(a)
# b = c = e != d
# this function do change original value
del change_like_mutable(arg):
arg.append(1)
arg.insert(0, 9)
arg.remove(2)
return
test_1 = [1, 2, 3]
change_like_mutable(test_1)
# this function doesn't
def wont_change_like_str(arg):
arg = [1, 2, 3]
return
test_2 = [1, 1, 1]
wont_change_like_str(test_2)
print("Doesn't change like a imutable", test_2)
This devil is not the reference / value / mutable or not / instance, name space or variable / list or str, IT IS THE SYNTAX, EQUAL SIGN.

Are functions being changed during assignment?

I thought I had a good handle on how Python passes objects (this article seemed enlightening).
Then I tried something simple, just assigning functions to variables.
class Thingy:
def __init__(self):
self.foo = {"egg": [1], "spam": [2]}
def calc(self):
self.foo["egg"][0] = 3
self.foo["spam"][0] = 4
def egg(self):
return self.foo["egg"][0]
def spam(self):
return self.foo["spam"]
thingy = Thingy()
x = thingy.egg()
y = thingy.spam()
print(x) # prints 1
print(y[0]) # prints 2
print(thingy.foo)
thingy.calc()
print(x) # prints 1 (???)
print(y[0]) # prints 4
print(thingy.foo)
I'm not entirely sure what's going on, especially as the value in the dictionary has been updated. My guess is that when the variable x is assigned, it is actually referring to a function whose return value has been evaluated to "1" already.
Is my understanding correct? I'd appreciate a clear explanation of why Python is deciding to treat .egg() and .spam() differently.
The statements
x = thingy.egg()
y = thingy.spam()
create x as an integer and y as a list. But what you must know is that the line y = thingy.spam() is just a shallow copy.
This is how shallow copy is defined by medium :
Shallow copy is a bit-wise copy of an object. A new object is created that has an exact copy of the values in the original object. If any of the fields of the object are references to other objects, just the reference addresses are copied i.e., only the memory address is copied.
So the variable y contains the address (or reference in more layman's term) to the elements of the list, and changing the list changes it also, unlike x where a new memory location is assigned.
when you run
x = thingy.egg()
thingy.egg() return an int witch has the same value as the one in foo["egg"][0] ans is than assigned to x whereas
y = thingy.spam()
thingy.spam() returns a list containing 4 witch is the same list as foo["spam"]. This has to do with object mutability. In your calculate function the 2 integers foo["egg"][0] and foo["spam"][0] are redefined with new objects. However the lists hey are contained in remaine as the same object. As x refers to the integer it remains the old object so 1 and y alsow stays as the same object however that object is a list and its first element now refers to the new int object witch is 4

Function that modifies an argument outside that function without using "return" python [duplicate]

This question already has answers here:
Why can a function modify some arguments as perceived by the caller, but not others?
(13 answers)
Closed 3 years ago.
Let's 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
Values of 'y' change but value 'a' stays the same. I have already learned that it's because one is mutable and the other is not. But how to change the code so that the function doesn't change the list?
For example to do something like that (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 on 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)
Here it doesn't work. Why? Again: how to avoid this problem? I understand why it is not working: yN = y[:] copies values of y to yN, but the values are also lists, so the operation would have to be doubled for every list in list. How to do this operation with nested lists?
Python variables contain pointers, or references, to objects. All values (even integers) are objects, and assignment changes the variable to point to a different object. It does not store a new value in the variable, it changes the variable to refer or point to a different object. For this reason many people say that Python doesn't have "variables," it has "names," and the = operation doesn't "assign a value to a variable," but rather "binds a name to an object."
In plusOne you are modifying (or "mutating") the contents of y but never change what y itself refers to. It stays pointing to the same list, the one you passed in to the function. The global variable y and the local variable y refer to the same list, so the changes are visible using either variable. Since you changed the contents of the object that was passed in, there is actually no reason to return y (in fact, returning None is what Python itself does for operations like this that modify a list "in place" -- values are returned by operations that create new objects rather than mutating existing ones).
In plusOne2 you are changing the local variable a to refer to a different integer object, 3. ("Binding the name a to the object 3.") The global variable a is not changed by this and continues to point to 2.
If you don't want to change a list passed in, make a copy of it and change that. Then your function should return the new list since it's one of those operations that creates a new object, and the new object will be lost if you don't 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 might be useful to have the function called either way, you can have the caller pass in x[:] if he wants a copy made.
Create a copy of the list. Using testList = inputList[:]. See the 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 the function
>>> def plusOne(y):
newList = []
for elem in y:
newList.append(elem+1)
return newList
You can also use a comprehension as others have pointed out.
>>> def plusOne(y):
return [elem+1 for elem in y]
You can pass a copy of your list, using slice notation:
print plusOne(y[:]), y
Or the better way would be to create the copy of list in the function itself, so that the caller don't have to worry about the possible modification:
def plusOne(y):
y_copy = y[:]
and work on y_copy instead.
Or as pointed out by #abarnet in comments, you can modify the function to use list comprehension, which will create a new list altogether:
return [x + 1 for x in y]
Just create a new list with the values you want in it and return that instead.
def plus_one(sequence):
return [el + 1 for el in sequence]
As others have pointed out, you should use newlist = original[:] or newlist = list(original) to copy the list if you do not want to modify 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 acheive your desired output with a list comprehension
def plusOne(y):
return [i+1 for i in y]
This will iterate over the values in y and create a new list by adding one to each of them
To answer your edited question:
Copying nested data structures is called deep copying. To do this in Python, use deepcopy() within the copy module.
You can do that by make a function and call this function by map function ,
map function will call the add function and give it the value after that it will print the new value like that:
def add(x):
return x+x
print(list(map(add,[1,2,3])))
Or you can use (*range) function it is very easy to do that like that example :
print ([i+i for i in [*range (1,10)]])

Python global vs. local variables — numbers and arrays treated differently [duplicate]

This question already has answers here:
Why can a function modify some arguments as perceived by the caller, but not others?
(13 answers)
Closed 3 years ago.
Let's 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
Values of 'y' change but value 'a' stays the same. I have already learned that it's because one is mutable and the other is not. But how to change the code so that the function doesn't change the list?
For example to do something like that (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 on 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)
Here it doesn't work. Why? Again: how to avoid this problem? I understand why it is not working: yN = y[:] copies values of y to yN, but the values are also lists, so the operation would have to be doubled for every list in list. How to do this operation with nested lists?
Python variables contain pointers, or references, to objects. All values (even integers) are objects, and assignment changes the variable to point to a different object. It does not store a new value in the variable, it changes the variable to refer or point to a different object. For this reason many people say that Python doesn't have "variables," it has "names," and the = operation doesn't "assign a value to a variable," but rather "binds a name to an object."
In plusOne you are modifying (or "mutating") the contents of y but never change what y itself refers to. It stays pointing to the same list, the one you passed in to the function. The global variable y and the local variable y refer to the same list, so the changes are visible using either variable. Since you changed the contents of the object that was passed in, there is actually no reason to return y (in fact, returning None is what Python itself does for operations like this that modify a list "in place" -- values are returned by operations that create new objects rather than mutating existing ones).
In plusOne2 you are changing the local variable a to refer to a different integer object, 3. ("Binding the name a to the object 3.") The global variable a is not changed by this and continues to point to 2.
If you don't want to change a list passed in, make a copy of it and change that. Then your function should return the new list since it's one of those operations that creates a new object, and the new object will be lost if you don't 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 might be useful to have the function called either way, you can have the caller pass in x[:] if he wants a copy made.
Create a copy of the list. Using testList = inputList[:]. See the 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 the function
>>> def plusOne(y):
newList = []
for elem in y:
newList.append(elem+1)
return newList
You can also use a comprehension as others have pointed out.
>>> def plusOne(y):
return [elem+1 for elem in y]
You can pass a copy of your list, using slice notation:
print plusOne(y[:]), y
Or the better way would be to create the copy of list in the function itself, so that the caller don't have to worry about the possible modification:
def plusOne(y):
y_copy = y[:]
and work on y_copy instead.
Or as pointed out by #abarnet in comments, you can modify the function to use list comprehension, which will create a new list altogether:
return [x + 1 for x in y]
Just create a new list with the values you want in it and return that instead.
def plus_one(sequence):
return [el + 1 for el in sequence]
As others have pointed out, you should use newlist = original[:] or newlist = list(original) to copy the list if you do not want to modify 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 acheive your desired output with a list comprehension
def plusOne(y):
return [i+1 for i in y]
This will iterate over the values in y and create a new list by adding one to each of them
To answer your edited question:
Copying nested data structures is called deep copying. To do this in Python, use deepcopy() within the copy module.
You can do that by make a function and call this function by map function ,
map function will call the add function and give it the value after that it will print the new value like that:
def add(x):
return x+x
print(list(map(add,[1,2,3])))
Or you can use (*range) function it is very easy to do that like that example :
print ([i+i for i in [*range (1,10)]])

Function changes list values and not variable values in Python [duplicate]

This question already has answers here:
Why can a function modify some arguments as perceived by the caller, but not others?
(13 answers)
Closed 3 years ago.
Let's 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
Values of 'y' change but value 'a' stays the same. I have already learned that it's because one is mutable and the other is not. But how to change the code so that the function doesn't change the list?
For example to do something like that (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 on 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)
Here it doesn't work. Why? Again: how to avoid this problem? I understand why it is not working: yN = y[:] copies values of y to yN, but the values are also lists, so the operation would have to be doubled for every list in list. How to do this operation with nested lists?
Python variables contain pointers, or references, to objects. All values (even integers) are objects, and assignment changes the variable to point to a different object. It does not store a new value in the variable, it changes the variable to refer or point to a different object. For this reason many people say that Python doesn't have "variables," it has "names," and the = operation doesn't "assign a value to a variable," but rather "binds a name to an object."
In plusOne you are modifying (or "mutating") the contents of y but never change what y itself refers to. It stays pointing to the same list, the one you passed in to the function. The global variable y and the local variable y refer to the same list, so the changes are visible using either variable. Since you changed the contents of the object that was passed in, there is actually no reason to return y (in fact, returning None is what Python itself does for operations like this that modify a list "in place" -- values are returned by operations that create new objects rather than mutating existing ones).
In plusOne2 you are changing the local variable a to refer to a different integer object, 3. ("Binding the name a to the object 3.") The global variable a is not changed by this and continues to point to 2.
If you don't want to change a list passed in, make a copy of it and change that. Then your function should return the new list since it's one of those operations that creates a new object, and the new object will be lost if you don't 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 might be useful to have the function called either way, you can have the caller pass in x[:] if he wants a copy made.
Create a copy of the list. Using testList = inputList[:]. See the 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 the function
>>> def plusOne(y):
newList = []
for elem in y:
newList.append(elem+1)
return newList
You can also use a comprehension as others have pointed out.
>>> def plusOne(y):
return [elem+1 for elem in y]
You can pass a copy of your list, using slice notation:
print plusOne(y[:]), y
Or the better way would be to create the copy of list in the function itself, so that the caller don't have to worry about the possible modification:
def plusOne(y):
y_copy = y[:]
and work on y_copy instead.
Or as pointed out by #abarnet in comments, you can modify the function to use list comprehension, which will create a new list altogether:
return [x + 1 for x in y]
Just create a new list with the values you want in it and return that instead.
def plus_one(sequence):
return [el + 1 for el in sequence]
As others have pointed out, you should use newlist = original[:] or newlist = list(original) to copy the list if you do not want to modify 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 acheive your desired output with a list comprehension
def plusOne(y):
return [i+1 for i in y]
This will iterate over the values in y and create a new list by adding one to each of them
To answer your edited question:
Copying nested data structures is called deep copying. To do this in Python, use deepcopy() within the copy module.
You can do that by make a function and call this function by map function ,
map function will call the add function and give it the value after that it will print the new value like that:
def add(x):
return x+x
print(list(map(add,[1,2,3])))
Or you can use (*range) function it is very easy to do that like that example :
print ([i+i for i in [*range (1,10)]])

Categories

Resources