user1927233
user1927233

Reputation: 151

Scope of list changes done in a function to called function

I have two functions foo() and bar(), which use two lists l1 and l2.

foo() makes a function call to bar() with l1 and l2 as arguments.

bar() mutates the lists l1 and l2. foo() needs to know of these changes to the lists hence the lists are returned by bar().

Instead of this passing of lists as arguments and returning them is there a better way to update the lists in foo()?

def bar(l1, l2):
     value=10
     l1.append(value)
     l2.append(value)
     return l1,l2

def foo() :
    list1=[]
    list2=[]
    list1, list2 = bar(list1,list2)

def main():
    foo()

if __name__ == '__main__':
    main()

Upvotes: 0

Views: 81

Answers (4)

inspectorG4dget
inspectorG4dget

Reputation: 113975

I have modified your code as follows:

def func2(list1, list2):
     value=10
     list1.append(value)
     list2.append(value)

def func1():
    list1=[]
    list2=[]
    func2(list1,list2)

Notice that func2 does not return anything. This is not a problem, since it uses list.append, which modifies the list IN-PLACE. This means that when func2 finishes execution, the changes to list1 and list2 still persist.

On the other hand, if you were to have done list1 = list1 + [5], that is a change that would not persist after func2 finished execution.

Thus, with the above code, func1 will be aware of changes made to the two lists by func2 even after the execution of func2 is complete.

In [13]: def func2(list1, list2):
   ....:     value = 'a'
   ....:     list1.append(value)
   ....:     list2.append(value)
   ....:     

In [14]: def func1():
   ....:     myList = []
   ....:     myOtherList = [1]
   ....:     print myList, myOtherList
   ....:     func2(myList, myOtherList)
   ....:     print myList, myOtherList
   ....:     

In [15]: func1()
[] [1]
['a'] [1, 'a']


In [16]: def otherfunc2(list1, list2):
   ....:     value = 'a'
   ....:     list1 = list1 + [value]
   ....:     list2 = list2 + [value]
   ....:     


In [17]: def func1():
   ....:     myList = []
   ....:     myOtherList = [1]
   ....:     print myList, myOtherList
   ....:     otherfunc2(myList, myOtherList)
   ....:     print myList, myOtherList
   ....:     

In [18]: func1()
[] [1]
[] [1]

Upvotes: -1

cdarke
cdarke

Reputation: 44364

Looking at your modified question, there is no need to return the lists, they are passed by reference anyway and will be modified:

def func2 (list1,list2):
     value=10
     list1.append(value)
     list2.append(value)

def func1() :
    list1=[]
    list2=[]
    func2(list1,list2)
    print "list1:",list1,"list2:",list2
    func2(list1,list2)
    print "list1:",list1,"list2:",list2
    func2(list1,list2)
    print "list1:",list1,"list2:",list2

def main():
    func1()

if __name__ == '__main__':
    main()

Gives:

list1: [10] list2: [10]
list1: [10, 10] list2: [10, 10]
list1: [10, 10, 10] list2: [10, 10, 10]

Upvotes: 0

abarnert
abarnert

Reputation: 365757

From your description and your comments, it sounds like your real func2 looks like this:

def func2(list1, list2):
    value = 'a'
    list1.append(value)
    list2.append(value)
    return list1,list2

This mutates list1 and list2 in place, so whoever calls it is going to see the changes. And it also returns list and list2, so whoever calls it can use the results that way.

So, in func1:

def func1() :
    list1=[]
    list2=[]
    func2(list1, list2)
    print(list1, list2)

You're going to see that both values are ['a'].

And if you do this:

(list1,list2) = func2([],[])
print(list1, list2)

You're also going to see that both values are ['a'].

You don't actually need—or usually want—to both mutate the values and return them. Just do one or the other:

def mutating_func2(list1, list2):
    value = 'a'
    list1.append(value)
    list2.append(value)

def non_mutating_func2(list1, list2):
    value = 'a'
    return list1+[value], list2+[value]

You can use mutating_func2 in code like func1, which just passes two lists and expects to have them modified. You can use non_mutating_func2 in code like your top-level code, which passes two lists and expects to get back two new lists. Both are perfectly reasonable things to do.

Upvotes: 0

Joran Beasley
Joran Beasley

Reputation: 113988

As others have mentioned since you are modifying the contents - in-place - of the lists passed in you do not need to return anything

def func2 (list1,list2):
     value=10
     list1.append(value)
     list2.append(value)

listA = [1,2,3]
listB = [7,8,9]

func2(listA,listB)

print listA
print listB

Upvotes: 2

Related Questions