Would you prefer using del or reassigning to None (garbage collecting)

Question:

Consider following code:

if value and self.fps_display is None:
    self.fps_display = clock.ClockDisplay()
elif not value and self.fps_display is not None:
    self.fps_display.unschedule()
    # Do this
    del self.fps_display
    # or this
    self.fps_display = None
    # or leave both in ?

Which is better python cleanup ?

Asked By: Red15

||

Answers:

There is no difference for garbage collection — in both cases a reference to object pointed to by self.fps_display will be released. Which one you should use depends on whether you want the name to still exist (albeit now pointing to a different object, None), or not.

Answered By: Cat Plus Plus

You have an object with an attribute, fps_display.

You shouldn’t make the attribute weirdly optional or sometimes missing.

If it’s a first-class attribute — and reasonably visible — it must be set to None to release any resources. Deleting the attribute is creepy because the object now has optional attributes and raises astonishing exceptions.

self.fps_display = None
Answered By: S.Lott

The difference is that self.fps_display = None will free whatever it referenced but keep the name around even though it’s just referencing None (which is a type, NoneType).

On the other hand del self.fps_display will completely remove both the name and what it referenced. If you thereafter try to use self.fps_display an AttributeError will be thrown (or NameError in case of a plain variable).

So in practice, by assigning None to a name you can still use it in expressions while using del the name is completely removed. In the first case a few bytes is needed to keep the name in memory, while the later completely clears all memory usage.

Some code to illustrate:

import sys
import gc

x = 'Some text here to give the variable a decent size'
y = 2
print('x value before deletion: {}'.format(x))
print('x size before deletion: {} bytes'.format(sys.getsizeof(x)))
print('y value before deletion: {}'.format(y))

x = None
del y
gc.collect() # Not really needed, just to show garbage collection has been done hereafter

print('x value after deletion: {}'.format(x))
print('x size after deletion: {} bytes'.format(sys.getsizeof(x))) # A few bytes needed to keep symbol name
print('x type after deletion: {}'.format(type(x)))

if not x:
    print('Can still use x!')

print('y value after deletion: {}'.format(y)) # Will throw NameError (AttributeError in case of class property)

Output:

x value before deletion: Some text here to give the variable a decent size
x size before deletion: 98 bytes
y value before deletion: 2
x value after deletion: None
x size after deletion: 16 bytes
x type after deletion: <class 'NoneType'>
Can still use x!
Traceback (most recent call last):
  File "Untitled.py", line 21, in <module>
    print('y value after deletion: {}'.format(y)) # Will throw NameError (AttributeError in case of class property)
NameError: name 'y' is not defined

Credits

Answered By: Andreas Bergström
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.