Reputation: 198867
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?
Upvotes: 483
Views: 413929
Reputation: 733
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.
Upvotes: 2
Reputation: 137
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'>
Upvotes: 2
Reputation: 298
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.
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[...]
Upvotes: 1
Reputation: 514
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
Upvotes: 1
Reputation: 1097
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
.
Upvotes: 6
Reputation: 357
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.
Upvotes: 13
Reputation: 185
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']
Upvotes: 3
Reputation: 2976
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.
locals()
.globals()
if x
belongs there.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()
.Upvotes: 12
Reputation: 171
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.
Upvotes: 0
Reputation: 45089
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.
Upvotes: 614
Reputation: 91680
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
Upvotes: 14
Reputation: 2251
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.
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
Upvotes: 28
Reputation: 198867
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.
Upvotes: 55
Reputation: 151
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
Upvotes: 15
Reputation: 703
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.
Upvotes: 4
Reputation: 31100
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.
Upvotes: 7
Reputation: 2399
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.
Upvotes: 22
Reputation: 21
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)
.
Upvotes: -2
Reputation: 830
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 :)
Upvotes: 2
Reputation: 156308
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.
Upvotes: 24
Reputation: 91149
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).
Upvotes: 3
Reputation: 994817
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.)
Upvotes: 201