0

This is just a question asking for the difference in the code.

I have several lists ie. a=[], b=[], c=[], d=[]

Say if I have a code that appends to each list, and I want to reset all these lists to its original empty state, I created a function:

def reset_list():
  del a[:]
  del b[:]
  del c[:]
  del d[:]

So whenever I call reset_list() in a code, it removes all the appended items and set all lists to []. However, the one below doesn't work:

def reset_list():
  a = []
  b = []
  c = [] 
  d = []

This might be a stupid question but I was wondering why the second one wouldn't work.

Vinci
  • 365
  • 1
  • 6
  • 16

4 Answers4

4

When you do del a[:] then it looks for the variable a (including outer contexts) and then performs del found_a[:] on it.

But when you use a = [] it creates a name a in the current context and assigns an empty list to it. When the function exits the variable a from the function is not "accessible" anymore (destroyed).

So in short the first works because you change the a from an outer context, the second does not work because you don't modify the a from the outer context, you just create a new a name and temporarily (for the duration of the function) assigns an empty list to it.

There's a difference between del a[:] and a = []

Note that these actually do something different which becomes apparent if you have additional references (aliases) to the original list. (as noted by @juanpa.arrivillaga in the comments)

del list[:] deletes all elements in the list but doesn't create a new list, so the aliases are updated as well:

>>> list_1 = [1,2,3]
>>> alias_1 = list_1
>>> del alist_1[:]
>>> list_1
[]
>>> alias_1
[]

However a = [] creates a new list and assigns that to a:

>>> list_2 = [1,2,3]
>>> alias_2 = list_2
>>> list_2 = []
>>> list_2
[]
>>> alias_2
[1, 2, 3]

If you want a more extensive discussion about names and references in Python I can highly recommend Ned Batchelders blog post on "Facts and myths about Python names and values".

A better solution?

In most cases where you have multiple variables that belong together I would use a class for them. Then instead of reset you could simply create a new instance and work on that:

class FourLists:
    def __init__(self):
        self.a = []
        self.b = []
        self.c = []
        self.d = []

Then you can create a new instance and work with the attributes of that instance:

>>> state = FourLists()
>>> state.a
[]
>>> state.b.append(10)
>>> state.b.extend([1,2,3])
>>> state.b
[10, 1, 2, 3]

Then if you want to reset the state you could simply create a new instance:

>>> new_state = FourLists()
>>> new_state.b
[]
MSeifert
  • 145,886
  • 38
  • 333
  • 352
1

You need to declare a,b,c,d as global if you want python to use the globally defined 'versions' of your variables. Otherwise, as pointed out in other answers, it will simply declare new local-scope 'versions'.

a = [1,2,3]
b = [1,2,3]
c = [1,2,3]
d = [1,2,3]

def reset_list():
    global a,b,c,d
    a = []
    b = []
    c = [] 
    d = []

print(a,b,c,d)
reset_list()
print(a,b,c,d)

Outputs:

[1, 2, 3] [1, 2, 3] [1, 2, 3] [1, 2, 3]
[] [] [] []

As pointed out by @juanpa.arrivillaga, there is a difference between del a[:] and a = []. See this answer.

Jeppe
  • 1,830
  • 3
  • 24
  • 33
  • 1
    Use _global_ at your own risk. – amanb Feb 08 '19 at 18:34
  • @juanpa.arrivillaga Right, see [this](https://stackoverflow.com/a/850831/3717691) answer. I think however OP is interested in why the changes aren't taking effect. – Jeppe Feb 08 '19 at 18:44
1

The 1st method works because:

  • reset_list() simply deletes the contents of the four lists. It works on the lists that you define outside the function, provided they are named the same. If you had a different name, you'd get an error:

    e = [1,2,3,4]
    def reset_list():
        del a[:]   #different name for list
    
    NameError: name 'e' is not defined
    

    The function will only have an effect if you initialize the lists before the function call. This is because you are not returning the lists back after the function call ends:

    a = [1,2,3,4] #initialize before function definition
    def reset_list():
        del a[:]
    
    reset_list() #function call to modify a
    print(a)
    #[]
    

    By itself the function does not return anything:

    print(reset_list())
    #None
    

The 2nd method doesn't work because:

  • the reset_list() function creates 4 empty lists that are not pointing to the lists that may have been defined outside the function. Whatever happens inside the function stays inside(also called scope) and ends there unless you return the lists back at the end of the function call. The lists will be modified and returned only when the function is called. Make sure that you specify the arguments in reset_list(a,..) in the function definition:

    #function definition
    def reset_list(a):
        a = []
        return a
    
    #initialize list after function call
    a = [1,2,3,4]
    print("Before function call:{}".format(a))
    new_a = reset_list(a)
    print("After function call:{}".format(new_a))
    #Output:
    Before function call:[1, 2, 3, 4]
    After function call:[]
    

As you've seen, you should always return from a function to make sure that your function "does some work" on the lists and returns the result in the end.

amanb
  • 5,276
  • 3
  • 19
  • 38
  • 1
    "The function will only have an effect if you initialize the lists before the function definition." This is not true. The list would have to be initialized *before the function is called*, not before it is defined. – juanpa.arrivillaga Feb 08 '19 at 22:24
  • In your first snippet shouldn't it be `NameError: name 'a' is not defined` (a instead of e), as it stands this is somwhat misleading because e is defined... – MSeifert Feb 08 '19 at 22:37
  • Thanks for pointing the error @juanpa.arrivillaga, just edited the answer. – amanb Feb 09 '19 at 02:57
0

The second function (with a = [ ] and so on) initialises 4 new lists with a local scope (within the function). It is not the same as deleting the contents of the list.

Trollsors
  • 492
  • 4
  • 17