Do self calling functions share lists with each other? [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 4 years ago.
I have a python script were I was experimenting with minmax AI. And so tried to make a tic tac toe game.
I had a self calling function to calculate the values and it used a variable called alist(not the one below) which would be given to it by the function before. it would then save it as new list and modify it.
This worked but when it came to back-tracking and viewing all the other possibilities the original alist variable had been changed by the function following it e.g.
import sys
sys.setrecursionlimit(1000000)
def somefunction(alist):
newlist = alist
newlist[0][0] = newlist[0][0] + 1
if newlist[0][0] < 10:
somefunction(newlist)
print(newlist)
thelist = [[0, 0], [0, 0]]
somefunction(thelist)
it may be that this is difficult to solve but if someone could help me it would be greatly appreciated

newlist = alist does not make a copy of the list. You just have two variable names for the same list.
There are several ways to actually copy a list. I usually do this:
newlist = alist[:]
On the other hand, that will make a new list with the same elements. To make a deep copy of the list:
import copy
newlist = copy.deepcopy(alist)

You probably want to deepcopy your list, as it contains other lists:
from copy import deepcopy
And then change:
newlist = alist
to:
newlist = deepcopy(alist)

Related

reverse list and append it to istelf [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 7 months ago.
Im trying to get a list to inputted in a function, and then the output would be the list, and then the reverse of the list added onto itself but for some reason whenever I reverse the variable reversal, it reverses list as well
def mirror(list):
reversel = list
reversel.reverse()
list.extend(reversel)
return list
test = ["alpha", "beta"]
print(mirror(test))
output
['beta', 'alpha', 'beta', 'alpha']
desired output
["alpha","beta","beta","alpha"]
You can use slicing:
def mirror(lst):
return lst + lst[::-1]
test = ["alpha", "beta"]
print(mirror(test)) # ['alpha', 'beta', 'beta', 'alpha']
An issue in the provided code is that (i) reversel = list (but don't use list as a name) does not copy the object, and (ii) reverse() reverses the list in place. These two lines of code, therefore, reverse the list list (as well as reversel). As a result, now list and reversel both are ["beta", "alpha"]. Then after list.extend(reversel), list becomes what you observe.
Also, there is another subtle issue; it is not generally recommended doing both of the following: (i) modify a given object, and (ii) return the object; this might cause confusion (I believe). It is better to do only one of them; modify an object in place (like reverse), or don't modify the object but return a modified copy of the object (like reversed).
Here is a solution without using reverse().
def mirror(list_to_mirror):
reversel = list_to_mirror
reversel = reversel[::-1]
#This is an equivilant to reverse()
list_to_mirror.extend(reversel)
return list_to_mirror
if __name__ == "__main__":
test = ["alpha", "beta"]
print(mirror(test))
This should work -
def mirror(list):
reversel = [i for i in list]
reversel.reverse()
list.extend(reversel)
return list
test = ["alpha", "beta"]
print(mirror(test))
when using '=' it stores the location of the variable. So when using a function like reverse, both values change.
A way that doesn't require creating and discarding a copy:
def mirror(lst):
lst += reversed(lst)
return lst

.pop to remove items from lists causes weird problems with variable scopes in python [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 2 years ago.
This one is making me absolutely crazy, so any help would be much appreciated. I have a program where I'm iterating through a list in a function. Here's a toy model of the problem:
masterList = ["person","woman","man","camera","television"]
workingList = masterList
def removeItem (workingList):
item = workingList.pop(2)
print("Test 1:",workingList)
removeItem(workingList)
print("Test 2:", workingList)
print("Test 3:", masterList)
As expected, "Test 1" prints out the list with an item removed.
However, "Test 2" also prints out the list with an item removed. I wasn't expecting that, but no matter. That's not the real problem, but I'm sure there's something I don't understand here about variable scopes and variable shadowing.
No the real problem is "Test 3", which as you can see, is printing out the masterList, which shouldn't even be touched by the removeItem function or the pop function within it. And yet, it too is printing out the list with an item removed.
How can this be happening, and how can I prevent it?
Thanks so much!
Cheers,
Ari
Python lists are mutable objects.
m = list([1, 2, 3])
n = m
a = 5
b = a
id(a) == id(b)
# id() return "identity" of the object.
# True, Both a and b are references to the same object.
id(m) == id(n)
# True, Both m and n are references to the same object.
b = b + 2
id(a) == id(b)
# False, a new object on separate location is created, which b will point.
n.pop()
id(m) == id(n)
# True, the object is mutated, and m and n still references to the same object.
Since, python lists are mutable, m and n will still be reference to the same object after mutation. Whereas, for immutable objects like int, a new object will be created and the identifier will refer to the new object.
Gist is, in your scenario, there has been only one object since python lists are mutable.
However, if you need the original list unchanged when the new list is modified, you can use the copy() method.
new_list = original_list.copy()
The ids of new_list and original_list is different.
Learn here about mutability in detail: https://medium.com/#meghamohan/mutable-and-immutable-side-of-python-c2145cf72747.
You have to make a copy of the masterList, otherwise workingList is nothing more than a reference.
If your list does not contain other containers (which yours doesn't), then a shallow copy is sufficient. There are numerous ways to make a shallow copy but slicing is the most optimal.
masterList = ["person","woman","man","camera","television"]
workingList = masterList[:] #copy via slice
a bunch of other ways to make a shallow copy
workingList = masterList * 1
workingList = masterList.copy()
workingList = list(masterList)
workingList = [*masterList]
import copy
workingList = copy.copy(masterList)
If you have a list that does possess something that holds a reference (like other containers, classes, etc), then you need to make a deepcopy.
import copy
a = [[1, 2, 3], ['a', 'b', 'c']]
b = copy.deepcopy(a)
Looks like I figured it out. The two lists are actually the same list unless you use list.copy()
So replacing the top two lines with:
masterList = ["person","woman","man","camera","television"]
workingList = masterList.copy()
makes everything perform as expected! Well, I still can't say I understand how the variable scopes work in their entirety, but at least this solves the major problem.

Python Theory About Equal Operator and Array Definition

I stumbled upon a theoretical question about how python works, and it got me puzzled. I tried to understand exactly what happened but couldn't find the answer in google - I'm a beginner, so I don't even know the terminology to make the apropriate search.
On the following code, when calling the function it changes myList, while I only wanted to create a list2 which was a copy of list1 (myList).
myList = [1,2,3,4,5,(1,2),(3,4)]
def onlyTuples(list1):
list2 = list1 # here is my question
for index,e in enumerate(list2):
if type(list2[index]) is not tuple:
list2[index] = (list2[index],)
return(list2)
print(myList)
create_new_list = onlyTuples(myList) # triggered by this call
print(myList)
It's all good if I change list2 = list1 to list2 = list(list1) and myList won't be changed when calling the function, but why?
The same thing doesn't happen with something like this:
a = 6
b = a
b = 7
print(a)
Any light upon the question will be appreciated. Thanks!
In python lists are passed by reference, so when you pass list to a function you pass its address in the memory. list2 = list1 won't create a copy of the list, it will save in list2 the address saved in list1. so change of list2 will change list1, but the function in the class list doesn't save the address, it copy a sequence to a list
To make a copy of a list, use:
newList = myList.copy()

How can I remove multiple elements from a list? [duplicate]

This question already has answers here:
Different ways of clearing lists
(8 answers)
Closed 4 years ago.
list1 = [2,5,61,7,10]
list1.remove(list1[0:len(list1)-1])
print(list1)
I want to remove all elements from that list but it shows me syntax error.
Any idea how can I remove all elements and print the final result like []
To remove all list items just use the in-built .clear() function:
>>> list1 = [2,5,61,7,10]
>>> list1.clear()
>>> print(list1)
[]
>>>
If you want to remove all elements from a list, you can use the slice assignment:
list1[:] = []
But with list.remove(), you can only do it one-by-one:
for item in list(list1):
list1.remove(item)
Note I created a copy of list1 with the for loop because it's dangerous to modify what you're iterating over, while it's safe to modify the list while iterating over a copy of it.
To remove some of the items:
for item in list1[0:3]:
list1.remove(item)
Or just better yet, use slice assignment:
list1[0:3] = []

python copying nested lists [duplicate]

This question already has answers here:
"Deep copy" nested list without using the deepcopy function
(5 answers)
Closed 4 years ago.
Let's say i have list a, and i want to copy it to b so that i can alter a but have its original form intact:
I use the traditional list() function...
a = [1,[2,3],4]
b = list(a)
print id(a), id(b)
# 2941136 35748600
a and b have different id, so the copying is a success. but list() did not copy the sublist -- altering a[1][0] will change b
a[1][0]=3
print b
# [1, [3, 3], 4]
I'm aware of copy.deepcopy() to solve this sort of problem, but i'm wondering if there are other ways of handling this without using a module.
One way to copy nested lists (given your example) is:
def deepcopy_nested_list(data):
out = []
for el in data:
if isinstance(el, list):
out.append(deepcopy_nested_list(el))
else:
out.append(el)
return out
This function copies the list to a new list and then recursively copies all nested lists to achieve a deep copy.
Please note that this does only create copies of lists and immutable objects (e.g., dicts are not copied). It shows only the idea how you would implement such a function and does not give a full implementation.
In real world code you would of course use copy.deepcopy().

Categories

Resources