2

I am a novice when it comes to using Python language. I want to understand why removing an item from a dictionary using the del keyword is impossible when someone references the item using a variable. It seems the del keyword only works if one uses the square bracket format i.e del dictionary[key] why is this so? I have provided a code snippet to help in understanding my question and guidance when it comes to answering the question (don't forget to mention the concept of id).

>>> personal_details = {'f_name': 'Imani', 'l_name': 'Ritcher', 'age': 25}
>>> first_name = personal_details['f_name']
>>> id(first_name)
139769037520176
>>> id(personal_details['f_name'])
139769037520176
>>> del first_name
>>> personal_details
{'f_name': 'Imani', 'l_name': 'Ritcher', 'age': 25}
>>> first_name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'first_name' is not defined
>>> del personal_details['f_name']
>>> personal_details
{'l_name': 'Ritcher', 'age': 25}
>>> 
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
Amani
  • 57
  • 4
  • Does this answer your question? [Are Python variables pointers? Or else, what are they?](https://stackoverflow.com/questions/13530998/are-python-variables-pointers-or-else-what-are-they) and/or https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference – JonSG Apr 24 '23 at 18:10
  • Given `a=1` and `b=a`, would you expect `del b` to also remove `a`? You shouldn't, and you shouldn't expect `del first_name` to remove `personal_details['f_name']` either. – Mark Tolonen Apr 24 '23 at 18:26

3 Answers3

2

When you call del first_name you are not calling del on a dictionary value. first_name simply contains the value for the key 'f_name' at the time of assignment. first_name has nothing otherwise to do with your dictionary besides containing one of its values.

Additionally, when you del a local variable such as first_name, you are removing it from the current scope. This means the variable name can be reused as if it had never existed in the current scope. This is why you get an error when you try to see the value of first_name after calling del on it here:

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

TL;TR In Python variables are technically references to objects, rather than the objects themselves.

When you create first_name (first_name = personal_details['f_name']), you are not creating any new object but a reference to already existing object (being the string Imani). Because f_name element in personal_details dict is also a reference to Imani, then after your assignment both first_name and personal_details['f_name'] point to the same object in memory. And that's why id() returns the same value for both variables.

Deleting is opposite. Use of del is not removing any object, but again, it deletes the reference that was created before. But the target object remains unaffected and that's why you can safely remove i.e. first_name and dict element is unaffected (and vice versa) even if they pointed to the same object. Finally, when you remove both references, then Imani become orphan and then it will be garbage collected by Python at some point.

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
  • Why is it that ``del personal_details['f_name'] deletes the dictionary item with the value ``Imani`` instead of just the reference (i.e ``f_name``)? This is despite the reference to ``Imani`` still existing via the ``first_name`` variable assuming it hasn't been deleted. (* I hope I made it clear) – Amani Apr 24 '23 at 20:15
  • 1
    You explicitly told Python to remove the element with key `f_name`. The value of this element is irrelevant. Once you removed that entry, whatever value it was holding, is also no longer needed. So the reference is removed as it is simply of no use. So removal of reference is consequence of the fact you remove the element that was using that particular reference. You can keep the key and still remove the reference by simply assigning another value (i.e. `foo[key] = None` or `foo[key] = 'bar'`). That would remove old reference and create new, to object holding new value. Did it help? – Marcin Orlowski Apr 24 '23 at 20:24
1

in my opinion it is easier to use dict.pop:

first_name = personal_details.pop('f_name', 'NoName')

in this case you get and delete key at the same time, if the key is already missing for some reason then first_name will get the value = 'NoName' from the second parameter (optional argument), not the KeyError exception

>>> personal_details = {'f_name': 'Imani', 'l_name': 'Ritcher', 'age': 25}
>>> first_name = personal_details.pop('f_name', 'NoName')
>>> id(first_name)
1835077383472
>>> id(personal_details['f_name'])
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    id(personal_details['f_name'])
KeyError: 'f_name'
>>> del first_name
>>> personal_details
{'l_name': 'Ritcher', 'age': 25}
>>> first_name
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    first_name
NameError: name 'first_name' is not defined
HWGuy
  • 11
  • 2