A posting today to the LiveJournal python_dev community wound up sort of asking why
del
has to be a Python builtin instead of a method. At first I thought this had a nice simple answer, but the more I thought about it the less obvious it became, and by the time I'd worked out a satisfying answer I'd had to really think about how Python fits together.
The short summary is that
del
needs to be a builtin because Python's object model is based on references and namespaces, and Python doesn't have a way to refer to your current namespaces (they have no explicit name).
Unlike in some languages,
del
does not literally delete objects; instead it removes references to them (which may as a side effect delete the object). In other words,
del
is not an object manipulation operation, it is a namespace manipulation operation. So the correct translation of '
del d
' to a method call version cannot be '
d.delete()
'; it has to be ' namespace
.delete("d")
'. But Python provides no magic namespace name for you to use for this operation, because
del
finds it implicitly. (Compound cases give the namespace; '
del d.c
' is explicitly operating on
d
's namespace and duly translates to
d.__delattr__("c")
.)
There are at least three such anonymous Python namespaces: globals, function locals (including closures), and the namespace of a class as it is being built. Of these, only the global namespace is really accessible; the latter two can only be gotten with magic, and even then you can't use
__delattr__
on them.
del
itself does internal interpreter magic to make it all go.
(Note that
locals()
is explicitly not a reference to the function's namespace; it is a dictionary copy of the function's current namespace. This is because functions don't implement their namespaces using Python dictionaries. Even for things that do implement their namespace using a Python
dict
, it's best considered an implementation detail.)
Sidebar: all but deleting yourself
While an object cannot literally delete itself in Python, it can try real hard, by scrubbing its __dict__ and changing its __class__ to something that does nothing. (Unfortunately you can't set your __class__ to plain
object
, as far as I can tell; you'll need to make an actual do-nothing class.)