List comprehension output [duplicate] - python

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 am trying to understand list comprehension by passing a list a of functions to act on list as shown in the code below.
def fun1(x):
x.append(5)
print(" In Fun 1:")
print(x)
return x
def fun2(x):
x.append(6)
return x
def fun3(x):
x.append(7)
return x
int_list = [1, 2, 3, 4]
funs_family = (fun1, fun2, fun3)
new_list = [fun(int_list) for fun in funs_family ]
print(new_list)
I am expecting the result of the new_list to be
[1,2,3,4,5] [1,2,3,4,5,6] [1,2,3,4,5,6,7]
but the actual result is
[1,2,3,4,5,6,7] [1,2,3,4,5,6,7] [1,2,3,4,5,6,7]
Can anyone explain why the actual result is different from expected result?

Return a new list in your fun_family methods and you will not see the issue:
def fun1(x):
x.append(5)
print("In Fun 1:")
print(x)
return list(x)
def fun2(x):
x.append(6)
return list(x)
def fun3(x):
x.append(7)
return list(x)
int_list = [1, 2, 3, 4]
funs_family = (fun1, fun2, fun3)
new_list = [fun(int_list) for fun in funs_family]
print(new_list)
>> [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6, 7]]

Here's a similar example for you to look at
int_list = [1, 2, 3, 4]
funs_family = (fun1, fun2, fun3)
new_list = [int_list for fun in funs_family]
int_list.append(5)
print(new_list)
Note that new_list does not depend on the functions at all, in fact they're never called. But what's printed is [1, 2, 3, 4, 5] three times. This is because the three lists inside new_list all point to the same list in memory. So when you change the original, it changes all of them.

Because you are appending to the list, it is actually the same object. At the end you are printing the exact same list three times. Instead, maybe what you want to do is create a new list within the function and add the int to it.
x = [1, 2, 3, 4]
x_copy = [i for i in x]
x_copy.append(5)

Each of the functions returns x.
So
new_list = [fun(int_list) for fun in funs_family ] print(new_list)
… returns three copies of x, all of which are equal to [1,2,3,4,5,6,7] once the comprehension has finished.
What you want instead are copies of x, which you can get using [:]:
new_list = [fun(int_list)[:] for fun in funs_family ]

Related

Extend list with another list in specific index? [duplicate]

This question already has an answer here:
list extend() to index, inserting list elements not only to the end
(1 answer)
Closed last month.
In python we can add lists to each other with the extend() method but it adds the second list at the end of the first list.
lst1 = [1, 4, 5]
lst2 = [2, 3]
lst1.extend(lst2)
Output:
[1, 4, 5, 2, 3]
How would I add the second list to be apart of the 1st element? Such that the result is this;
[1, 2, 3, 4, 5 ]
I've tried using lst1.insert(1, *lst2) and got an error;
TypeError: insert expected 2 arguments, got 3
For those who don't like reading comments:
lst1 = [1, 4, 5]
lst2 = [2, 3]
lst1[1:1] = lst2
print(lst1)
Output:
[1, 2, 3, 4, 5]
If your only goal is to get the list sorted correctly, then you use .extend() and .sort() afterwards.
You can solve your problem in two steps:
Insert the list into the other list
Flatten the result
Code:
from collections.abc import Iterable
# https://stackoverflow.com/questions/2158395/flatten-an-irregular-arbitrarily-nested-list-of-lists
def flatten(xs):
for x in xs:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
yield from flatten(x)
else:
yield x
xs = [1,4,5]
ys = [2,3]
xs.insert(1, ys)
print("intermediate result", xs)
xs = flatten(xs)
print(xs)

Recursion with list but I got some [..]

I tried to create a problem like [0,1,2,[0,1,2,[0,1,2,[0,1,2] ] ]... by using recursion it but it got some bugs that I don't know where it came from.
It creates an output like this:
[1, 2, 3, 4, 5, [...]]
So let's make an example x = [1,2,3,4,5] and len_ = len(x) for the recursion. The code will be like this:
list_ = [1,2,3,4,5]
n = len(list_)
dull = []
def BlastedField3(n):
global list_
list_ += [list_]
if n == 1:
return list_
if n > 1:
return list_
return BlastedFild(n-1)
print(BlastedField3(n))
So I was imagining that list_ += [list_] was something like per each recursion of the function the list_ += [list_] working too.But! it works but the bug [...] is coming up next to it.
Is there a way to solve this without this bug [...] or just try a loop?
The problem of creating a self-containing list can be solved by not using references but shallow copies and by not reusing global variables (whenever you feel the need for those, look at your design long and hard).
base = [1,2,3,4,5]
def blasted(n):
if n <= 1:
return base[:] # shallow copy to never accidentally expose your base
return base + [blasted(n-1)]
>>> blasted(1)
[1, 2, 3, 4, 5]
>>> blasted(2)
[1, 2, 3, 4, 5, [1, 2, 3, 4, 5]]
>>> blasted(3)
[1, 2, 3, 4, 5, [1, 2, 3, 4, 5, [1, 2, 3, 4, 5]]]
Actually the use of shallow copies is not strictly necessary as the code never mutates the base list. But I would still recommend it because if someone were to mutate any result of the blast, base might be affected.

Unwanted list changing through functioncall

The general project is to re-build an enigma machine. However, the problem is this:
I have a list and I want to rearrange it in a way that the first element is appended to the same list and then the first element is deleted.
Basicly, I want this:
l = [1, 2, 3, 4]
l_new = [2, 3, 4, 1]
for this purpose I constructed the function
def switch_up(list):
list.append(list[0])
del list[0]
return list
The problem: When calling this function with a list, it does not only return the changed list, but changes the original list given as the argument.
The full code looks like this:
def switch_up(list):
list.append(list[0])
del list[0]
return list
my_list = [1, 2, 3, 4]
my_list2 = switch_up(my_list)
print(my_list)
print(my_list2)
My expected/desired output would be:
[1, 2, 3, 4]
[2, 3, 4, 1]
The output I get is:
[2, 3, 4, 1]
[2, 3, 4, 1]
You are altering the list passed into the function. That isn't a copy of the list it's the same list. You should just make a copy and return it with something like:
def switch_up(l):
# list slices will make shallow copy
return l[1:] + l[:1]
my_list = [1, 2, 3, 4]
my_list2 = switch_up(my_list)
print(my_list)
# [1, 2, 3, 4]
print(my_list2)
# [2, 3, 4, 1]
Lists are mutable in python and therefore it is assumed, that you want to do operations on the original list. If you do not want that you have to manually copy your list for example with list.copy. For more information on copy please see this stackoverflow question
All you created is a "pointer" called my_list2 to the same value as my_list if you would for example iclude my_list2[1] = 'a' the result would be:
my_list = [2, 'a', 4, 1]
my_list2 = [2, 'a', 4, 1]
And btw you should never name your variables the same as inbuilt functions, like list

Issue with pop() and append() [duplicate]

This question already has answers here:
python list by value not by reference [duplicate]
(11 answers)
Closed 3 years ago.
Any help will be greatly appreciated!!!
res = []
s = [1,2,3,4,5,6]
s.pop()
res.append(s)
print res
s.pop()
res.append(s)
print res
The above python code gives the following result
[[1, 2, 3, 4, 5]]
[[1, 2, 3, 4], [1, 2, 3, 4]]
I don't understand why pop on s will affect res. I mean the print result should be
[[1,2,3,4,5]]
[[1,2,3,4,5],[1,2,3,4]]
This is OK - because res will hold the same reference as s(to the same object- in this case the array).
To solve this problem use this:
res = []
s = [1,2,3,4,5,6]
s.pop()
res.append(list(s))
print res
s.pop()
res.append(list(s))
print res
also take a look at :
How to clone or copy a list?
python: Appending a dictionary to a list - I see a pointer like behavior
Every value in Python is a reference (pointer) to an object.
Assignment always copies the value (which is a pointer); two such
pointers can thus point to the same object.
To get the needed result you need to copy the initial list:
res = []
s = [1,2,3,4,5,6]
s.pop()
res.append(s[:])
print(res)
s.pop()
res.append(s[:])
print(res)
The same can be done using list.copy() function:
...
res.append(s.copy())
...
The output:
[[1, 2, 3, 4, 5]]
[[1, 2, 3, 4, 5], [1, 2, 3, 4]]

Trouble with a function that simulates reverse attribute in python

I have this function to simulate reverse() in python:
My_list = [[1, 3, "s"], 2, 2, 3, 4, 2]
def listRev(list):
list=list[::-1]
print list
listRev(My_list)
print My_list
The function gives me correct reversed list but I expect when I print My_list in the last line, the code print reversed My_list not My_list itself. How can I solve my problem?
If you want to simulate reverse, you must modify the list passed as a parameter to you function, not simply use a new list in your function.
When you write list=list[::-1] the local copy of the original parameter points to a new list. You should do instead :
def rev(l):
l[:] = l[::-1]
print (l)
The usage of l[:] asks Python to replace the content of the list, and not to make the variable point to a new list.
This can be solved by returning a list from the function
My_list = [[1, 3, "s"], 2, 2, 3, 4, 2]
def listRev(list):
list=list[::-1]
print list
return list
My_list = listRev(My_list)
print My_list
This is because lists are not passed by reference in Python.
Post Comment Edit
If you want the function to be in place only for My_list even though it is very wrong and bad programming to do so, you can use this
My_list = [[1, 3, "s"], 2, 2, 3, 4, 2]
def listRev():
global My_list
My_list = My_list[::-1]
listRev()
print My_list

Categories