"backtracking" variables in python del function - python

The del statement in python, when applied to a list, does something very strange. It not only deletes the entry in the list in question, but also "backtracks" to delete the same element in whatever list the variable was derived from.
For instance:
>>> x
[1, 2, 3, 4, 5]
>>> z=x
>>> del z[1]
>>> z
[1, 3, 4, 5]
>>> x
[1, 3, 4, 5]
In other words, even though I apply delete to z, the deletion is also applied to x. This "backtracking" doesn't come up with any other commands or functions, e.g.
>>> x=[1,2,3,4,5]
>>> z=x
>>> z+[6]
[1, 2, 3, 4, 5, 6]
>>> x
[1, 2, 3, 4, 5]
applying the add function to z leaves x unaffected, as it very well should.
This is causing me all sorts of headaches with the delete 'NA' scrip that I'm working on. Do you know what's going on with the del statement, and how can I get around this problem so that if I set z=x and then apply del to z, x remains unchanged?

z = x does not make a copy of the list. z and x now point to the same list. Any modification of that list will be visible through both names, z and x.
With z + [6], you did not assign the result back to z. Try printing z after doing that. It will be unchanged, just like x.
z += [6] would be necessary to assign the result back to z and it would have the same behavior as your first example.
You can copy the list using one of these methods:
z = x[:]
z = list(x)

Related

Only if I'm not using __iadd__, I get TypeError: can only concatenate list (not "str") to list [duplicate]

consider the following code:
>>> x = y = [1, 2, 3, 4]
>>> x += [4]
>>> x
[1, 2, 3, 4, 4]
>>> y
[1, 2, 3, 4, 4]
and then consider this:
>>> x = y = [1, 2, 3, 4]
>>> x = x + [4]
>>> x
[1, 2, 3, 4, 4]
>>> y
[1, 2, 3, 4]
Why is there a difference these two?
(And yes, I tried searching for this).
__iadd__ mutates the list, whereas __add__ returns a new list, as demonstrated.
An expression of x += y first tries to call __iadd__ and, failing that, calls __add__ followed an assignment (see Sven's comment for a minor correction). Since list has __iadd__ then it does this little bit of mutation magic.
The first mutates the list, and the second rebinds the name.
1)'+=' calls in-place add i.e iadd method. This method takes two parameters, but makes the change in-place, modifying the contents of the first parameter (i.e x is modified). Since both x and y point to same Pyobject they both are same.
2)Whereas x = x + [4] calls the add mehtod(x.add([4])) and instead of changing or adding values in-place it creates a new list to which a points to now and y still pointing to the old_list.

How to add new value to a list without using 'append()' and then store the value in a newly created list?

I have been trying this a lot.
>>> x = [4,5]
>>> y = x.append(7)
>>> print y
None
>>>print x
[4, 5, 7]
How is this possible?
When I trying storing the values in the new list y and the print it, it results in None and it also changes the current list `x.
Is there any other way to do this in Python?
Because the function append() modifies the list and returns None.
One of the best practices to do what you want to do is by using + operator.
Let's take your example :
>>> x = [4, 5]
>>> y = x + [7]
>>> x
[4, 5]
>>> y
[4, 5, 7]
The + operator creates a new list and leaves the original list unchanged.
This is possible because x.append() is a method of list x that mutates the list in-place. There is no need for a return value as all the method needs to do is perform a side effect. Therefore, it returns None, which you assign your variable y.
I think you want to either create a copy of x and append to that:
y = x[:]
y.append(7)
or assign y the result of a list operation that actually creates a new list:
y = x + [7]
You can do
x = [4,5]
y = x + [7]
# x = [4, 5]
# y = [4, 5, 7]
The y is None because the append() method doesn't return the modified list (which from your code you are expecting).
So you can either split the statement,
y = x.append(7)
into
x.append(7)
y = x
OR use,
y = x + [7]
The second statement is more cleaner and creates a new list from x.
Just a note: Updating y won't make any updates in x as in the first statement it does. If you want to avoid this use copy.copy
Using Extend,
x = [3,4]
y =[]
y.extend(x+[7])
print(x, y)
produces output :
[3, 4] [3, 4, 7]
[Program finished]

Modifying list slice passed into a function

Is it possible to pass a slice of a list into a function and modify the list via the slice?
This doesn't seem to work:
def foo(a_list):
a_list[0]='abc'
x=[1,2,3,4]
foo(x[0:2])
I want x to now be x=['abc',2,3,4]
No. A "list slice" in the sense you describe is nothing but a new list. When you do x[0:2], the resulting list does not "know" that it was created as a slice of another list. It's just a new list.
What you could do is pass in the slice object itself, separately from the list:
def foo(a_list, a_slice):
a_list[a_slice]='abc'
>>> foo(x, slice(0, 2))
>>> x
['a', 'b', 'c', 3, 4]
No! Slices create copies of lists (see the documentation). You can do this:
>>> x = [1, 2, 3, 4]
>>> x[1:3] = [7, 8, 9]
>>> X
[1, 7, 8, 9, 4]
But, when you get a new list from a slicing operation, it's a copy, and thus changes to it won't affect the original:
>>> x = [1, 2, 3, 4]
>>> y = x[1:3]
>>> y[0] = 5
>>> y
[5, 3]
>>> x
[1, 2, 3, 4]
def foo(a_list):
a_list[0]='abc'
return a_list
x=[1,2,3,4]
foo(x) #it returns x=['abc',2,3,4]
Assumably you're trying to pass in x[0:2], rather than x[0,2], but the reason it doesn't work is because when you create a slice you are creating a subarray copy of x.
You are not operating on the same instance of that array, what you are doing is passing an entirely new array. Passing in 'x' alone would work, but passing in x[0:2] would not unless you specifically wrote it as x[0:2] = foo(x[0:2]) and had foo() return a_list.
As brenns10 explained, slices create a copy (even in python 3.0) of your origional data.
You could do something like the following:
def foo(x):
x[0] = 'abc'
return x
x = [0, 1, 2, 3]
x[0:2] = foo(x[0:2]) # x = ['abc', 1, 2, 3]
While this gives you the desired outcome, it doesn't exactly work as you would want. This could be problematic if needing to perform large slices as you'd have to perform a lot of copying.

python implementation of list append [duplicate]

consider the following code:
>>> x = y = [1, 2, 3, 4]
>>> x += [4]
>>> x
[1, 2, 3, 4, 4]
>>> y
[1, 2, 3, 4, 4]
and then consider this:
>>> x = y = [1, 2, 3, 4]
>>> x = x + [4]
>>> x
[1, 2, 3, 4, 4]
>>> y
[1, 2, 3, 4]
Why is there a difference these two?
(And yes, I tried searching for this).
__iadd__ mutates the list, whereas __add__ returns a new list, as demonstrated.
An expression of x += y first tries to call __iadd__ and, failing that, calls __add__ followed an assignment (see Sven's comment for a minor correction). Since list has __iadd__ then it does this little bit of mutation magic.
The first mutates the list, and the second rebinds the name.
1)'+=' calls in-place add i.e iadd method. This method takes two parameters, but makes the change in-place, modifying the contents of the first parameter (i.e x is modified). Since both x and y point to same Pyobject they both are same.
2)Whereas x = x + [4] calls the add mehtod(x.add([4])) and instead of changing or adding values in-place it creates a new list to which a points to now and y still pointing to the old_list.

Different behaviour for list.__iadd__ and list.__add__

consider the following code:
>>> x = y = [1, 2, 3, 4]
>>> x += [4]
>>> x
[1, 2, 3, 4, 4]
>>> y
[1, 2, 3, 4, 4]
and then consider this:
>>> x = y = [1, 2, 3, 4]
>>> x = x + [4]
>>> x
[1, 2, 3, 4, 4]
>>> y
[1, 2, 3, 4]
Why is there a difference these two?
(And yes, I tried searching for this).
__iadd__ mutates the list, whereas __add__ returns a new list, as demonstrated.
An expression of x += y first tries to call __iadd__ and, failing that, calls __add__ followed an assignment (see Sven's comment for a minor correction). Since list has __iadd__ then it does this little bit of mutation magic.
The first mutates the list, and the second rebinds the name.
1)'+=' calls in-place add i.e iadd method. This method takes two parameters, but makes the change in-place, modifying the contents of the first parameter (i.e x is modified). Since both x and y point to same Pyobject they both are same.
2)Whereas x = x + [4] calls the add mehtod(x.add([4])) and instead of changing or adding values in-place it creates a new list to which a points to now and y still pointing to the old_list.

Categories

Resources