Is the use of del bad?

2024/11/20 18:34:37

I commonly use del in my code to delete objects:

>>> array = [4, 6, 7, 'hello', 8]
>>> del(array[array.index('hello')])
>>> array
[4, 6, 7, 8]
>>> 

But I have heard many people say that the use of del is unpythonic. Is using del bad practice?

>>> array = [4, 6, 7, 'hello', 8]
>>> array[array.index('hello'):array.index('hello')+1] = ''
>>> array
[4, 6, 7, 8]
>>> 

If not, why are there many ways to accomplish the same thing in python? Is one better than the others?

Option 1: using del

>>> arr = [5, 7, 2, 3]
>>> del(arr[1])
>>> arr
[5, 2, 3]
>>> 

Option 2: using list.remove()

>>> arr = [5, 7, 2, 3]
>>> arr.remove(7)
>>> arr
[5, 2, 3]
>>> 

Option 3: using list.pop()

>>> arr = [5, 7, 2, 3]
>>> arr.pop(1)
7
>>> arr
[5, 2, 3]
>>> 

Option 4: using slicing

>>> arr = [5, 7, 2, 3]
>>> arr[1:2] = ''
>>> arr
[5, 2, 3]
>>> 

I am sorry if this question appears to be opinion-based, but I am looking for a reasonable answer to my question, and I will add a bounty after 2 days if I don't get a suitable answer.

Edit:

Since there are many alternates to using del to delete certain parts of objects, the one unique factor left of del is its ability to remove objects completely:

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

However, what is the point of using it to 'undefine' objects?

Also, why does the following code change both variables:

>>> a = []
>>> b = a
>>> a.append(9)
>>> a
[9]
>>> b
[9]
>>> 

But the del statement does not achieve the same effect?

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

The other answers are looking at it from a technical point of view (i.e. what's the best way to modify a list), but I would say the (much) more important reason people recommend, for example, slicing, is that it doesn't modify the original list.

The reason for this in turn is that usually, the list came from somewhere. If you modify it, you can unknowningly cause serious and hard-to-detect side effects, which can cause bugs elsewhere in the program. Or even if you don't cause a bug immediately, you'll make your program overall harder to understand and reason about, and debug.

For example, list comprehensions/generator expressions are nice in that they never mutate the "source" list they are passed:

[x for x in lst if x != "foo"]  # creates a new list
(x for x in lst if x != "foo")  # creates a lazy filtered stream

This is of course often more expensive (memory wise) because it creates a new list but a program that uses this approach is mathematically purer and easier to reason about. And with lazy lists (generators and generator expressions), even the memory overhead will disappear, and computations are only executed on demand; see http://www.dabeaz.com/generators/ for an awesome introduction. And you should not think too much about optimization when designing your program (see https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil). Also, removing an item from a list is quite expensive, unless it's a linked list (which Python's list isn't; for linked list, see collections.deque).


In fact, side-effect free functions and immutable data structures are the basis of Functional Programming, a very powerful programming paradigm.

However, under certain circumstances, it's OK to modify a data structure in place (even in FP, if the language allows it), such as when it's a locally created one, or copied from the function's input:

def sorted(lst):ret = list(lst)  # make a copy# mutate retreturn ret

— this function appears to be a pure function from the outside because it doesn't modify its inputs (and also only depends on its arguments and nothing else (i.e. it has no (global) state), which is another requirement for something to be a Pure Function).

So as long as you know what you're doing, del is by no means bad; but use any sort of data mutation with extreme care and only when you have to. Always start out with a possibly less efficient but more correct and mathematically elegant code.

...and learn Functional Programming :)

P.S. note that del can also be used to delete local variables and thus eliminate references to objects in memory, which is often useful for whatever GC related purposes.


Answer to your second question:

As to the second part of your question about del removing objects completely — that's not the case: in fact in Python, it is not even possible to tell the interpreter/VM to remove an object from memory because Python is a garbage collected language (like Java, C#, Ruby, Haskell etc) and it's the runtime that decides what to remove and when.

Instead, what del does when called on a variable (as opposed to a dictionary key or list item) like this:

del a

is that it only removes the local (or global) variable and not what the variable points to (every variable in Python holds a pointer/reference to its contents not the content itself). In fact, since locals and globals are stored as a dictionary under the hood (see locals() and globals()), del a is equivalent to:

del locals()['a']

or del globals()['a'] when applied to a global.

so if you have:

a = []
b = a

you're making a list, storing a reference to it in a and then making another copy of that reference and storing it into b without copying/touching the list object itself. Therefore, these two calls affect one and the same object:

a.append(1)
b.append(2)# the list will be [1, 2]

whereas deleting b is in no way related to touching what b points to:

a = []
b = a
del b
# a is still untouched and points to a list

Also, even when you call del on an object attribute (e.g. del self.a), you're still actually modifying a dictionary self.__dict__ just like you are actually modifying locals()/globals() when you do del a.

P.S. as Sven Marcnah has pointed out that del locals()['a'] does not actually delete the local variable a when inside a function, which is correct. This is probably due to locals() returning a copy of the actual locals. However, the answer is still generally valid.

https://en.xdnf.cn/q/26294.html

Related Q&A

Find how many lines in string

I am creating a python movie player/maker, and I want to find the number of lines in a multiple line string. I was wondering if there was any built in function or function I could code to do this:x = &…

AttributeError: Cant get attribute new_block on module pandas.core.internals.blocks

I was using pyspark on AWS EMR (4 r5.xlarge as 4 workers, each has one executor and 4 cores), and I got AttributeError: Cant get attribute new_block on <module pandas.core.internals.blocks. Below is…

Disable python import sorting in VSCode

I am trying to disable vscode from formatting my python imports when I save my file. I have some code that must run in between various imports so order is important, but every time I save it just shove…

Log-log lmplot with seaborn

Can Seaborns lmplot plot on log-log scale? This is lmplot with linear axes: import numpy as np import pandas as pd import seaborn as sns x = 10**arange(1, 10) y = 10** arange(1,10)*2 df1 = pd.DataFra…

Django on IronPython

I am interested in getting an install of Django running on IronPython, has anyone had any success getting this running with some level of success? If so can you please tell of your experiences, perfo…

How to create a DataFrame while preserving order of the columns?

How can I create a DataFrame from multiple numpy arrays, Pandas Series, or Pandas DataFrames while preserving the order of the columns?For example, I have these two numpy arrays and I want to combine …

Dynamically limiting queryset of related field

Using Django REST Framework, I want to limit which values can be used in a related field in a creation. For example consider this example (based on the filtering example on https://web.archive.org/web/…

How to clear GPU memory after PyTorch model training without restarting kernel

I am training PyTorch deep learning models on a Jupyter-Lab notebook, using CUDA on a Tesla K80 GPU to train. While doing training iterations, the 12 GB of GPU memory are used. I finish training by sav…

cryptography is required for sha256_password or caching_sha2_password

Good day. Hope your all are well. Can someone help me with fix this? Im new to the MySQL environment. Im trying to connect to MySQL Database remotely. I used the following python code and got this err…

Django: How to access original (unmodified) instance in post_save signal

I want to do a data denormalization for better performance, and put a sum of votes my blog post receives inside Post model:class Post(models.Model):""" Blog entry """autho…