How to delete all the items (in a list) beautifully?

Hello!
I want to know how to delete all the items (in a list) beautifully?
For example: list = [2, 3, 4]
Can I just do it in this way? list = [] :thinking:
Or del list[2], del list[1], del list[0] :joy:
:melting_face:Thank you for your time!

del list[:]

2 Likes

Thanks so much!

For the record list.clear() does the same thing.
Also naming a variable list is not a good practice, as list is a buitin that is used to build lists.

5 Likes

Just to note, this does not delete any items in the list. It simply creates a new empty list and assigns it to the name list. Perhaps list was the only reference to the old list, and it will be reclaimed now that its reference count is 0, but any other references will still see the original list [2, 3, 4].

x = [1,2,3]
y = x
x = []
assert y == [1,2,3]

Using list.clear() guarantees that the list itself is emptied, and all references (not just list) will see the list as empty. (So would del list[:]; I’m not aware of any significant difference in semantics.)

3 Likes
1 Like

You are right! Thanks!

That’s right! I understand now, thanks so much

:partying_face:Thank you!

WOW, so does Python also have the function of ‘garbage collection’ like Java? That’s great!

As a heads-up, you can click the heart icon on posts to “like” them instead of writing separate personalized thank-you notes. (And yes, Python is a garbage-collected language.)

3 Likes

del list slice always existed. dicts with started with or gained .clear to abbreviate deleting each key (and value) in a list. Beginners used list.clear by analogy so it was eventually added instead of raising NameError. So there are 2 obvious ways, depending on where one starts.

2 Likes

In my view, deleting a slice isn’t obvious - it requires a bit of lateral thinking if you haven’t seen it before. Calling clear is a lot more obvious even if you haven’t seen it on analogous things - it’s a coherent, specific thing you’d want to do with the list, so there’s a reasonable expectation of the functionality being built-in. A separate function wouldn’t work because the operation is inherently mutating, whereas some containers are immutable.

For that matter, deleting a slice isn’t the only “lateral thinking” option, either. For example, one could use slice assignment: mylist[:] = [].

So, for a while the language was missing what it “should” have had. Which happens; we can’t all be Dutch (or not) :wink:

Why bless you, it all depends!

How do you remove one thing from a list? del stuff[3] How do you remove a set of things from a list? del stuff[2:4] How do you remove all from the beginning, or all to the end? del stuff[:2] and del stuff[4:] So how do you remove them all? del stuff[:]

I have become very happily accustomed to “projection” notations. It’s the same kind of idea of “do this on everything”. In Pike, for example, I can refer to one array element as func(stuff[3]) or all array elements with func(stuff[*]) - it calls the function with every element and returns an array with the results. Python’s slice notation is the same thing, but more flexible, since you can make partial slices (although I will admit, stuff[:] isn’t nearly as obvious for the “all items” case as stuff[*] is). If you’re used to working with subscripts “in bulk”, so to speak, it makes a lot of sense, and makes so many algorithms so much easier to work with.

1 Like

list *= 0

2 Likes

Not that it makes much of a difference (we are talking about a few dozen ns here), but for small lists list.clear() is about 3x faster :innocent: than del list[:] (Python3.11 on Linux).

2 Likes

How small and how did you measure?

My results with lst = list(range(5)):

  7.4 ± 0.0 ns  pass  # as baseline
 30.3 ± 0.1 ns  lst.clear()
 47.9 ± 0.1 ns  lst *= 0
 67.0 ± 0.2 ns  del lst[:]
 76.4 ± 0.2 ns  lst[:] = ()
 94.6 ± 0.2 ns  lst[:] = []

Python: 3.11.4 (main, Sep  9 2023, 15:09:21) [GCC 13.2.1 20230801]
script
from timeit import timeit
from statistics import mean, stdev
import sys
import random

funcs = '''\
lst.clear()
del lst[:]
lst[:] = []
lst[:] = ()
lst *= 0
pass  # as baseline
'''.splitlines()

times = {f: [] for f in funcs}
def stats(f):
    ts = [t * 1e9 for t in sorted(times[f])[:10]]
    return f'{mean(ts):5.1f} ± {stdev(ts):3.1f} ns '
for _ in range(100):
    random.shuffle(funcs)
    for f in funcs:
        t = timeit(
            'for lst in lists: ' + f,
            'lst = list(range(5)); lists = [lst[:] for _ in range(10**4)]',
        number=1
        ) / 10**4
        times[f].append(t)
for f in sorted(funcs, key=stats):
    print(stats(f), f)

print('\nPython:', sys.version)

Attempt This Online!

3 Likes

I tested for the empty list and range(10). To measure small snippets of code I tend to use ipython %timeit feature, that runs loops to properly measure execution time. To profile larger things I recommend using a proper profiler.

With range(10), how did you avoid that %timeit’s loop repeatedly cleared the same list, i.e., that it didn’t really clear any elements in loop iterations after the first?