osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

REPL, global, and local scoping


I got hit on the head and decided to try to write something of a Python interpreter for embedding. I'm starting to get into the ugly stuff like scoping. This has been a good way to learn the real deep details of the language. Here's a situation:

>>> meow = 10
>>> def vartest():
...     x = 1
...     y = 2
...     def first():
...        x = 3
...        meow = 11
...        return x
...     def second():
...        y = 4
...        meow = 12
...        return y
...     return first() + second() + x + y + meow
...
>>> vartest()
20

first() and second() are messing with their own versions of x and y. Side note: the peephole optimizer doesn't just slap a 3 and 4 on the stack, respectively, and just return that. It'll actually do a STORE_NAME to 0 for each. The meow variable is more peculiar. The first() and second() inner functions are working on their own copy. However, vartest() is using the one from the calling scope, which is the REPL.

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?

I tripped on this in my unit tests when I was trying to note that a class' constructor had run successfully without getting into poking the class' variables. I was trying to have it set a variable in the parent scope that I'd just query after the test.

It looks like in practice, that should totally not work at all:
>>> meow = 10
>>> class Foo:
...    def __init__(self):
...       meow = 11
...
>>> f = Foo()
>>> meow
10

...and it's on me to carve out a throwaway inner meow variable. But hey, let's kick meow up to the class level:

>>> meow = 10
>>> class Foo:
...    meow = 11
...    def __init__(self):
...       pass
...
>>> f = Foo()
>>> meow
10

So I guess it's a different ballgame for classes entirely. What are the rules in play here for:
1. A first-level function knowing to use a variable globally
2. A Second-level function using the name locally and uniquely
3. Classes having no visibility to upper-level variables at all by default