On Wed, Mar 20, 2019 at 1:31 PM <adam.pre...@gmail.com> wrote: > > On Tuesday, March 19, 2019 at 3:48:27 PM UTC-5, Chris Angelico wrote: > > > I can see in vartest() that it's using a LOAD_GLOBAL for that, yet > > > first() and second() don't go searching upstairs for a meow variable. > > > What is the basis behind this? > > > > > > > Both first() and second() assign to the name "meow", so the name is > > considered local to each of them. In vartest(), the name isn't > > assigned, so it looks for an outer scope. > > Thanks for the responses. I wanted to poke on this part just a little bit > more. I want to mimic the proper behavior without having to go back to it > repeatedly. > > Let's say I'm parsing this code and generating the byte code for it. I run > into meow on the right side of an expression but never the left. At this > point, do I always generate a LOAD_GLOBAL opcode? Is that done whether or not > I know if the variable is defined in a higher scope? That's what it looks > like from renaming it to something I didn't define. I just want to double > check. > > On the interpreter side seeing the opcode, does that generally mean I walk up > the variables I have in higher frames until I either run out of them or find > it? > > Does that mean defining "global meow" basically states "always use > LOAD/STORE_GLOBAL opcodes for this one, even if it shows up on the left side > of an assignment first?" >
I would recommend parsing in two broad steps, as CPython does: 1) Take the source code and turn it into an abstract syntax tree (AST). This conceptualizes the behaviour of the code more-or-less the way the programmer wrote it. 2) Implement the AST in byte-code. The AST for your first() function looks something like this: FunctionDef( name='first', args=arguments(args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[ Assign( targets=[Name(id='x', ctx=Store())], value=Constant(value=3, kind=None), type_comment=None ), Assign( targets=[Name(id='meow', ctx=Store())], value=Constant(value=11, kind=None), type_comment=None ), Return( value=Name(id='x', ctx=Load()) ) ], decorator_list=[], returns=None, type_comment=None ) (I got this by using ast.parse() and ast.dump() from the CPython 3.8 standard library. If you use a different version or interpreter, it may look slightly different, but it'll be broadly similar.) Since there are Assign entries with targets saying Name "x" and Name "meow", you know that both those names are local to the function. So you create local-to-function bytecode. But if you had a "global meow" statement in that function (which translates to an AST node of Global(names=['meow']) ), you would create STORE_GLOBAL opcodes, and similarly, any names not assigned in the local scope would be looked up globally. Of course, life's never this simple, and there are myriad other considerations. But hopefully that will help with an understanding of what Python's doing. ChrisA -- https://mail.python.org/mailman/listinfo/python-list