464

I can't really think of any reason why Python needs the del keyword (and most languages seem to not have a similar keyword). For instance, rather than deleting a variable, one could just assign None to it. And when deleting from a dictionary, a del method could be added.

Is there a reason to keep del in Python, or is it a vestige of Python's pre-garbage collection days?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jason Baker
  • 192,085
  • 135
  • 376
  • 510
  • 56
    **Historical note**: Python had garbage collection from the beginning. Prior to 2.0, Python's garbage collector could not detect cycles of references, but that had nothing to do with `del`. – Steven Rumbalski May 27 '11 at 02:05
  • 32
    @Steven Rumbalksi, it does have something to do with del. Del was used to break reference cycles. – Winston Ewert May 27 '11 at 03:24
  • 9
    but `del` isn't a vestigate of pre-garbage collection because you could always have `used = None`. It's just always made sense to have specific syntax for it. Since we have cylical GC now, the cases where you want to use either is small. – Winston Ewert May 27 '11 at 04:01
  • 3
    > and most languages seem to not have a similar keyword Most *garbage collected* languages don't (or only use it to hint to the GC that it can collect a variable). Most older language did : - Good old BASIC languages such as QuickBasic had [`ERASE`](http://www.qbasic.net/en/reference/qb11/Statement/ERASE.htm) (kill specific variables) and [`CLEAR`](https://robhagemans.github.io/pcbasic/doc/#CLEAR) (kill *all* variables) – DrYak Apr 25 '18 at 09:06

22 Answers22

599

Firstly, you can del other things besides local variables

del list_item[4]
del dictionary["alpha"]

Both of which should be clearly useful. Secondly, using del on a local variable makes the intent clearer. Compare:

del foo

to

foo = None

I know in the case of del foo that the intent is to remove the variable from scope. It's not clear that foo = None is doing that. If somebody just assigned foo = None I might think it was dead code. But I instantly know what somebody who codes del foo was trying to do.

ndmeiri
  • 4,979
  • 12
  • 37
  • 45
Winston Ewert
  • 44,070
  • 10
  • 68
  • 83
  • 66
    +1, yes. When you assign something, it conveys an intent to use it later. I've only really seen `del` used in memory-intensive calculations, but when I saw it I realised immediately why it was necessary. – detly May 27 '11 at 02:07
  • 22
    The use-case of deleting from a list or dictionary could easily be replaced with a method (as I noted in the question). I'm not sure I *agree* with the use of `del` to signal intent (as a comment could do the same without adding to the language), but I suppose that's the best answer. – Jason Baker Dec 14 '12 at 17:59
  • 6
    @JasonBaker, granted on the methods. Deleting slices and such would more awkward using a method though. Yes, you could use a comment. But I think using a statement is better then a comment as its part of the language. – Winston Ewert Dec 15 '12 at 15:19
  • 2
    @JasonBaker: It's not only about the intent, those two syntaxes do two very different things. – Pavel Šimerda Sep 21 '14 at 07:28
  • @PavelŠimerda, what two syntaxes? – Winston Ewert Sep 22 '14 at 01:52
  • 1
    I meant the two options. Removing a variable is an entirely different type of action from assigning a variable a placeholder value like `None`. – Pavel Šimerda Sep 22 '14 at 08:09
  • @PavelŠimerda, I think that misses the point of the OP. Both syntaxes have different semantics. But the only use case for `del var` is also handled by `var = None`. So the OP thinks there is no point in the `del var` syntax. – Winston Ewert Sep 23 '14 at 04:43
  • 3
    It's also handled by deleting it from the respective dictionary. You could also dispute the `len()` function the same way. If this is the case, the quesition may have been closed as opinion or even taste based. Python simply tends to provide primitives for basic operations instead of relying on methods. – Pavel Šimerda Sep 23 '14 at 11:26
  • 2
    Btw, when you have a huge loop with many generated variables that spawn entire memory, `del` becomes immensely useful, as it deletes the variable, while `var = None` still keeps it in the scope, using 4-8 bytes for it – SMSk May 17 '16 at 12:01
  • @SMSk, actually no. Python preallocates memory to hold all the variables in a function. Deleting one won't release the memory. – Winston Ewert May 17 '16 at 15:45
  • @WinstonEwert that's true, but you can call gc.collect() and free up unreferenced memory, while `var = None` keeps the reference to the `var` in scope – SMSk May 17 '16 at 16:17
  • 1
    @SMSk, no. The preallocated array for the variables in a function will be kept alive as long as the function is. Calling `gc.collect()` will not change that. – Winston Ewert May 17 '16 at 17:37
  • 1
    It is also a good security measure when refactoring code. If you have a large function using lots of local variables and you come to a point at which you are sure, a specific variable is not used anymore, you can `del` it and if you reuse the name after that, you can be sure it was initialized with a new value first. – Bachsau Mar 18 '18 at 15:37
  • 3
    When you try it on a python interpreter: if you create `var` and delete it with `del var` and then call `var` again, there will be an error "NameError: name 'var' is not defined". But, if you create `var` and delete it with `var = None` and then call `var` after, nothing happens, not even an error. Based on what has been said before, does it mean that the "name" with `del` is deleted but not the memory allocation ? Does it mean that with `var = None` method, the memory is freed but not the name ? – BuzzRage Jun 11 '18 at 15:25
  • 1
    @BuzzRage, in practice removing the name from the local scope via `del` sets some pointer somewhere to NULL. That doesn't cause any change in memory allocation. However, if that was the last reference to `var`, the value itself will be deallocated. – Winston Ewert Jun 12 '18 at 16:15
  • The "clearer intent" thing has another benefit: if you have a function which has to take some parameters to fulfill an interface but does not use them, you can `del` those parameters on the first line of the function. This not only clearly indicates your intent, but it also makes sure that the code works as intented (either 1. you intended to not use those variables and the code works without using them, or 2. there is no other good reason for `del` to be the first line of a function, and if the variables are actually used the code will throw an error about it.) – mtraceur Feb 16 '21 at 21:40
199

There's this part of what del does (from the Python Language Reference):

Deletion of a name removes the binding of that name from the local or global namespace

Assigning None to a name does not remove the binding of the name from the namespace.

(I suppose there could be some debate about whether removing a name binding is actually useful, but that's another question.)

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 25
    -1 The poster clearly already understands this, he's asking why you want would to remove a name binding. – Winston Ewert May 27 '11 at 01:59
  • 94
    @Winston Ewert: I'm not sure the poster understood that `del` removes a name binding as he suggested assigning `None` as an alternative. – Steven Rumbalski May 27 '11 at 02:22
  • 8
    @Steven, the poster clearly contrasts deleting the variable (removing the name) and assigning None. He doesn't see why you should delete the variable when you can just assign None. The have the same effect in that they release the reference to whatever was previously bound to that name. – Winston Ewert May 27 '11 at 03:25
  • 24
    @Winston Ewert: It's not clear to me. Perhaps it's clear to you in that you state that they "have the same effect in that the release the reference to whatever was previously bound to that name." But that's (clearly?) not the whole story in that an attempt to use a name after deleting it raises a `NameError`. Greg Hewgill makes this very distinction. And it's this distinction that makes your assertion of what the poster "clearly" understood unclear to me. – Steven Rumbalski May 27 '11 at 03:39
  • 1
    @Steven, I think the fact that the OP mentions "deleting the variable" suggests that he's aware of the difference between it and assigning None to it. Regardless, the question is why its *useful*, Greg doesn't attempt to answer that. – Winston Ewert May 27 '11 at 03:51
  • 10
    @Winston Ewert I don't agree. But enough said. We've both made our cases. – Steven Rumbalski May 27 '11 at 12:23
52

One place I've found del useful is cleaning up extraneous variables in for loops:

for x in some_list:
  do(x)
del x

Now you can be sure that x will be undefined if you use it outside the for loop.

Jason Baker
  • 192,085
  • 135
  • 376
  • 510
26

Deleting a variable is different than setting it to None

Deleting variable names with del is probably something used rarely, but it is something that could not trivially be achieved without a keyword. If you can create a variable name by writing a=1, it is nice that you can theoretically undo this by deleting a.

It can make debugging easier in some cases as trying to access a deleted variable will raise an NameError.

You can delete class instance attributes

Python lets you write something like:

class A(object):
    def set_a(self, a):
        self.a=a
a=A()
a.set_a(3)
if hasattr(a, "a"):
    print("Hallo")

If you choose to dynamically add attributes to a class instance, you certainly want to be able to undo it by writing

del a.a
Bernhard
  • 2,084
  • 2
  • 20
  • 33
24

There is a specific example of when you should use del (there may be others, but I know about this one off hand) when you are using sys.exc_info() to inspect an exception. This function returns a tuple, the type of exception that was raised, the message, and a traceback.

The first two values are usually sufficient to diagnose an error and act on it, but the third contains the entire call stack between where the exception was raised and where the the exception is caught. In particular, if you do something like

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    if something(exc_value):
        raise

the traceback, tb ends up in the locals of the call stack, creating a circular reference that cannot be garbage collected. Thus, it is important to do:

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    del tb
    if something(exc_value):
        raise

to break the circular reference. In many cases where you would want to call sys.exc_info(), like with metaclass magic, the traceback is useful, so you have to make sure that you clean it up before you can possibly leave the exception handler. If you don't need the traceback, you should delete it immediately, or just do:

exc_type, exc_value = sys.exc_info()[:2]

To avoid it all together.

SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
22

Just another thinking.

When debugging http applications in framework like Django, the call stack full of useless and messed up variables previously used, especially when it's a very long list, could be very painful for developers. so, at this point, namespace controlling could be useful.

tdihp
  • 2,329
  • 2
  • 23
  • 40
  • 1
    This is my exact use case. I only discovered the `del` keyword recently, and it really clears things like that up. – Nat Riddle Jan 29 '21 at 20:47
15

Using "del" explicitly is also better practice than assigning a variable to None. If you attempt to del a variable that doesn't exist, you'll get a runtime error but if you attempt to set a variable that doesn't exist to None, Python will silently set a new variable to None, leaving the variable you wanted deleted where it was. So del will help you catch your mistakes earlier

Matt
  • 151
  • 1
  • 2
14

del is often seen in __init__.py files. Any global variable that is defined in an __init__.py file is automatically "exported" (it will be included in a from module import *). One way to avoid this is to define __all__, but this can get messy and not everyone uses it.

For example, if you had code in __init__.py like

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

Then your module would export the sys name. You should instead write

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

del sys
asmeurer
  • 86,894
  • 26
  • 169
  • 240
12

To add a few points to above answers: del x

Definition of x indicates r -> o (a reference r pointing to an object o) but del x changes r rather than o. It is an operation on the reference (pointer) to object rather than the object associated with x. Distinguishing between r and o is key here.

  • It removes it from locals().
  • Removes it from globals() if x belongs there.
  • Removes it from the stack frame (removes the reference physically from it, but the object itself resides in object pool and not in the stack frame).
  • Removes it from the current scope. It is very useful to limit the span of definition of a local variable, which otherwise can cause problems.
  • It is more about declaration of the name rather than definition of content.
  • It affects where x belongs to, not where x points to. The only physical change in memory is this. For example if x is in a dictionary or list, it (as a reference) is removed from there(and not necessarily from the object pool). In this example, the dictionary it belongs is the stack frame (locals()), which overlaps with globals().
a_guest
  • 34,165
  • 12
  • 64
  • 118
Sohail Si
  • 2,750
  • 2
  • 22
  • 36
10

I've found del to be useful for pseudo-manual memory management when handling large data with Numpy. For example:

for image_name in large_image_set:
    large_image = io.imread(image_name)
    height, width, depth = large_image.shape
    large_mask = np.all(large_image == <some_condition>)
    # Clear memory, make space
    del large_image; gc.collect()

    large_processed_image = np.zeros((height, width, depth))
    large_processed_image[large_mask] = (new_value)
    io.imsave("processed_image.png", large_processed_image)

    # Clear memory, make space
    del large_mask, large_processed_image; gc.collect()

This can be the difference between bringing a script to a grinding halt as the system swaps like mad when the Python GC can't keep up, and it running perfectly smooth below a loose memory threshold that leaves plenty of headroom to use the machine to browse and code while it's working.

Nerve
  • 317
  • 2
  • 8
7

Force closing a file after using numpy.load:

A niche usage perhaps but I found it useful when using numpy.load to read a file. Every once in a while I would update the file and need to copy a file with the same name to the directory.

I used del to release the file and allow me to copy in the new file.

Note I want to avoid the with context manager as I was playing around with plots on the command line and didn't want to be pressing tab a lot!

See this question.

Community
  • 1
  • 1
Lee
  • 29,398
  • 28
  • 117
  • 170
  • I had something similar with loaded Images with the Python Image Library (PIL). I open an image, and if it had certain dimensions, I wanted to delete the file; however the file was still in use by Python. Therefore, I said 'del img', and then could remove the file. – physicalattraction Oct 10 '14 at 11:39
  • 2
    Beware that this is an implementation detail as the language specification doesn't guarantee when the `__del__()` method on garbage objects is called or even _if_ it gets called at all. So APIs which offer no way to release ressources other than hoping the `__del__()` method gets called some time (soon after the object is garbage) are broken to some degree. – BlackJack Aug 13 '15 at 14:52
6

I would like to elaborate on the accepted answer to highlight the nuance between setting a variable to None versus removing it with del:

Given the variable foo = 'bar', and the following function definition:

def test_var(var):
    if var:
        print('variable tested true')
    else:
        print('variable tested false')

Once initially declared, test_var(foo) yields variable tested true as expected.

Now try:

foo = None
test_var(foo)

which yields variable tested false.

Contrast this behavior with:

del foo
test_var(foo)

which now raises NameError: name 'foo' is not defined.

jacob
  • 828
  • 8
  • 13
4

As an example of what del can be used for, I find it useful i situations like this:

def f(a, b, c=3):
    return '{} {} {}'.format(a, b, c)

def g(**kwargs):
    if 'c' in kwargs and kwargs['c'] is None:
        del kwargs['c']

    return f(**kwargs)

# g(a=1, b=2, c=None) === '1 2 3'
# g(a=1, b=2) === '1 2 3'
# g(a=1, b=2, c=4) === '1 2 4'

These two functions can be in different packages/modules and the programmer doesn't need to know what default value argument c in f actually have. So by using kwargs in combination with del you can say "I want the default value on c" by setting it to None (or in this case also leave it).

You could do the same thing with something like:

def g(a, b, c=None):
    kwargs = {'a': a,
              'b': b}
    if c is not None:
        kwargs['c'] = c

    return f(**kwargs)

However I find the previous example more DRY and elegant.

Jocke
  • 673
  • 3
  • 8
3

When is del useful in python?

You can use it to remove a single element of an array instead of the slice syntax x[i:i+1]=[]. This may be useful if for example you are in os.walk and wish to delete an element in the directory. I would not consider a keyword useful for this though, since one could just make a [].remove(index) method (the .remove method is actually search-and-remove-first-instance-of-value).

ninjagecko
  • 88,546
  • 24
  • 137
  • 145
  • 8
    `[].pop(index)` and `[].remove(item)`. Don't use variable named `"index"` when talking about value, makes it look confusing. – Ski May 15 '14 at 10:43
  • @Ski pop does use [index](https://docs.python.org/2/tutorial/datastructures.html#more-on-lists). This is a valid answer whereas half these answers just give an example using del where None would also work. A list object set to None is still in the list whereas del removes the items. – user5389726598465 Jun 13 '18 at 10:40
2

The "del" command is very useful for controlling data in an array, for example:

elements = ["A", "B", "C", "D"]
# Remove first element.
del elements[:1]
print(elements)

Output:

['B', 'C', 'D']

Victor Marrerp
  • 157
  • 1
  • 4
2

I think one of the reasons that del has its own syntax is that replacing it with a function might be hard in certain cases given it operates on the binding or variable and not the value it references. Thus if a function version of del were to be created a context would need to be passed in. del foo would need to become globals().remove('foo') or locals().remove('foo') which gets messy and less readable. Still I say getting rid of del would be good given its seemingly rare use. But removing language features/flaws can be painful. Maybe python 4 will remove it :)

fuzzy-waffle
  • 830
  • 5
  • 11
2

del deletes the binding of the variable and its object that it points to.

>>> a = ['a', 'b', 'c']
>>> b = a
>>> del a
>>> b
['a', 'b', 'c']
>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

A simple use case I can think of would be in case you have used a built-in function name as a variable, and you want to use that function after it has been already "overridden" by your variable name.

t = ('a', "letter")
value, type = t
print(value, type)
del type
print(type(value))

Output:

a letter
<class 'str'>
nullptr
  • 127
  • 9
1

Another niche case, but useful.

from getpass import getpass

password = getpass()
token = get_auth_token(password)
del password

# Assume more code here...

After the deletion of the password variable, you don't run the risk of it being printed out later by mistake, or otherwise ending up in a log or stack trace.

Community
  • 1
  • 1
Dustin
  • 693
  • 8
  • 20
0

Yet another niche usage: In pyroot with ROOT5 or ROOT6, "del" may be useful to remove a python object that referred to a no-longer existing C++ object. This allows the dynamic lookup of pyroot to find an identically-named C++ object and bind it to the python name. So you can have a scenario such as:

import ROOT as R
input_file = R.TFile('inputs/___my_file_name___.root')
tree = input_file.Get('r')
tree.Draw('hy>>hh(10,0,5)')
R.gPad.Close()
R.hy # shows that hy is still available. It can even be redrawn at this stage.
tree.Draw('hy>>hh(3,0,3)') # overwrites the C++ object in ROOT's namespace
R.hy # shows that R.hy is None, since the C++ object it pointed to is gone
del R.hy
R.hy # now finds the new C++ object

Hopefully, this niche will be closed with ROOT7's saner object management.

Amnon Harel
  • 151
  • 1
  • 4
0

del is removing the variable from the current scope unless it is re-initialized. Setting it to None keeps it in the current scope.

a = "python string"        
print(a)
del a
print(a)
a = "new python string"
print(a)

Output:

python string
Traceback (most recent call last):
  File "testing.py", line 4, in <module>
    print(a)
NameError: name 'a' is not defined
Gaurav Srivastava
  • 504
  • 1
  • 4
  • 12
0

As I have not seen a interactive console answer, I'll be showing one.

When foo=None that reference and the object exist, it's not pointing to it.

While del foo destroys the object and reference too.

Interactive output

So if you do something like this if foo is None and it was deleted it will rise NameError as the the reference, it's object and everything in between was deleted with del

Deletion of a target list recursively deletes each target, from left to right.

Meanwhile foo=None is just a reference pointing to None so the reference is still kicking, same for the object.

[...]In Python, variables are references to objects and any variable can reference any object[...]

Link to quote 1

Link to quote 2

dmb
  • 288
  • 2
  • 9
-2

Once I had to use:

del serial
serial = None

because using only:

serial = None

didn't release the serial port fast enough to immediately open it again. From that lesson I learned that del really meant: "GC this NOW! and wait until it's done" and that is really useful in a lot of situations. Of course, you may have a system.gc.del_this_and_wait_balbalbalba(obj).

Adam Wagner
  • 15,469
  • 7
  • 52
  • 66
  • 5
    Hmm... That really should not have made a difference. Although, perhaps your issue was fixed by the extra delay it introduced? – Winston Ewert Nov 28 '12 at 22:09
  • 3
    I don't think you can back the *GC this now* by any documentation. I think relying on GC and calling to `__del__()` is always wrong in Python (I don't know the reasons for this design, though) and it's better to use context manager API (the `with` statement). – Pavel Šimerda Sep 21 '14 at 07:31
  • 1
    That's some kind of voodoo programming. See the method description and the note in the [documentation for object.__del__()](https://docs.python.org/2/reference/datamodel.html#object.__del__) for details, _and_ keep in mind this only describes CPythons current implementation with reference counting. Other Python implementations (PyPy, Jython, IronPython, Brython, …) or future CPython implementations may use a different garbage collection scheme. Jython uses the JVMs GC which doesn't delete objects immediately. The `serial` module also works with Jython so your _hack_ doesn't work there! – BlackJack Aug 13 '15 at 15:05
  • BTW [gc.collect](https://docs.python.org/2/library/gc.html#gc.collect) would be the way to explicitly recycle. Supported in most python implementations . – tdihp Oct 28 '15 at 01:21