pythonpython-3.xlistglobaloperand

Using list as operand


I am running into a problem when passing a list to a function. It appears to have a global effect on the list variable, but I did not declare it as global in my function. Can anyone tell me what's happening and how to work around it?

def a_Minus_b(a,b):
    for i in range(len(b)):
        print("a= ", a)
        if b[i] in a:
            a.remove(b[i])
    return a

x = [1,2,3,4]
a_Minus_b(x,x)
a=  [1, 2, 3, 4]
a=  [2, 3, 4]
a=  [2, 4]

Error:

Traceback (most recent call last):
  File "<pyshell#115>", line 1, in <module>
    a_Minus_b(x,x)
  File "<pyshell#112>", line 4, in a_Minus_b
    if b[i] in a:
IndexError: list index out of range

Solution

  • Python functions can mutate their arguments, if the argument itself is mutable and python lists are.

    If you want to have you function without side effects, copy the data first.

    def a_minus_b(a, b):
        a = list(a) # makes a copy and assigns the copy to a new *local* variable
        for val in b:
            print("a = ", a)
            if val in a:
                a.remove(val)
        return a
    

    instead of

    a = list(a)
    

    you can use any of:

    from copy import copy, deepcopy
    
    
    a = a[:]         # copies only the references in the list
    a = a.copy()     # copies only the references in the list
    a = copy(a)      # copies only the references in the list
    a = deepcopy(a)  # creates copies also of the items in the list
    

    Also, what you are doing is builtin in python, it is the filter function. It takes an iterable and a function and returns only the elements of the iterable where the function evaluates to True.

    print(list(filter(a, lambda elem: elem in b))
    

    filter returns an iterator, to convert it into a list, call list on it.