In python, an object is subscriptable when it's class defines a
__getitem__(self, k)
method, allowing us to "get items" through the bracket syntax:
obj[k]
The syntax for the builtin del function is:
del(obj[k])
This deletes item k from (subscriptable) object obj. But apparently, without calling the special getitem method.
See example below
>>> class A:
... def __init__(self, d):
... self._d = d
...
... def __getitem__(self, k):
... print("Calling __getitem__")
... return self._d[k]
...
... def __delitem__(self, k):
... del(self._d[k])
...
>>>
>>> a = A({1: 'one', 2: 'two', 3: 'three'})
>>> a._d
{1: 'one', 2: 'two', 3: 'three'}
>>> a[2]
Calling __getitem__
'two'
>>> del(a[2])
>>> # Note there was no "Calling __getitem__" print!
So it seems like before a[2] forwards the work to the getitem method, the interpreter is aware of the del context, and bypasses it, calling directly
a.__delitem__(2)
instead.
How does that work?
And most of all: Is this mechanism customizable?
Could I for example, write a function foo so that
foo(obj[k])
doesn't ever call
obj.__getitem__(k)
but instead, for example,
obj.foo(k)
del
is not a function. It can do this because it's not a function. This is why it's not a function. It's a keyword built into the language as part of the del
statement.
To keep in mind that things like del
and return
aren't functions (and avoid unexpected precedence surprises), it's best to not put parentheses around the "argument":
del whatever
rather than
del(whatever)
del
does not take an object and delete it. The thing to the right of del
is not an expression to be evaluated. It is a target_list, the same kind of syntax that appears on the left side of the =
in an assignment statement:
target_list ::= target ("," target)* [","]
target ::= identifier
| "(" [target_list] ")"
| "[" [target_list] "]"
| attributeref
| subscription
| slicing
| "*" target
To delete a subscription target like obj[k]
, Python evaluates the expression obj
and the expression k
to produce two objects, then calls the __delitem__
method of the first object with the second object as the argument. obj[k]
is never evaluated as an expression, though pieces of it are.
This all relies on compiler and grammar support, and cannot be done for arbitrary user-defined functions.