On Wed, Oct 18, 2017 at 3:19 AM, bartc <b...@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 -- https://mail.python.org/mailman/listinfo/python-list