why del is not a function or method?

Chris Angelico rosuav at gmail.com
Tue Oct 17 16:05:09 EDT 2017


On Wed, Oct 18, 2017 at 3:19 AM, bartc <bc at freeuk.com> wrote:
> On 17/10/2017 16:44, Terry Reedy wrote:
>
>> In CPython left-hand expressions are not merely quoted for runtime
>> evaluation and use.  They are parsed at compile time and compiled to almost
>> normal bytecode.  The difference is that a load bytecode is replace by a
>> store bytecode (that takes a second argument).
>
>
> What does the second argument do?
>
> I thought Load and Store were of equal rank.

CPython's byte code is a stack-based processor. So "load X" means
"push X onto the stack", and "store X" means "pop the top of the stack
and store it into X". For simple names, those are perfect
counterparts. But for dotted or subscripted lookups, it's like this:

>>> dis.dis("x[1]=y[2]")
  1           0 LOAD_NAME                0 (y)
              2 LOAD_CONST               0 (2)
              4 BINARY_SUBSCR
              6 LOAD_NAME                1 (x)
              8 LOAD_CONST               1 (1)
             10 STORE_SUBSCR
             12 LOAD_CONST               2 (None)
             14 RETURN_VALUE

(Ignore the last two lines - they're an implicit "return None" at the
end of the "function" that I just compiled.)

Loading y[2] is done in several steps. First, we get the value of y
(which could be an arbitrary expression; in this case, it's just a
simple name). Then, we take the constant that we're subscripting with
(the integer 2). Finally, we do a BINARY_SUBSCR, which is the
square-bracket lookup operator. That leaves us with something on the
stack. The load took one argument (the name "y"), and then the
subscripting was a separate operation with two arguments (y and 2).

Storing into x[1], on the other hand, is collapsed down a bit. We
first load up the value of x (again, that could be any expression),
and then the subscript (the integer 1). Then the subscripting and
assignment are done in one STORE_SUBSCR operation; it takes three
arguments off the stack (the new value, the object, and the
subscript), and leaves nothing behind.

You can also look at it from the POV of the dunder methods that let
you customize this.

>>> class Foo:
    def __getitem__(self, item):
        print("Getting", item)
        return 42
    def __setitem__(self, item, value):
        print("Setting", item, "to", value)

>>> Foo()[1] = Foo()[2]
Getting 2
Setting 1 to 42

The setting operation needs to know the object (self), the subscript
(item), and the new value.

Does that make sense?

ChrisA



More information about the Python-list mailing list