I'm reading a wiki book Python_Programming and I'm a little confused about the piece of code below:
def foo():
def bar():
x=5
return x+y
y=10
return bar()
foo()
well, I notice that y
is defined outside of bar() and it's used in x+y
, which is "before" y
is defined. I think similar code will cause a compiling error in C and we have to write something like:
def foo():
def bar(y):
x=5
return x+y
y=10
return bar(y)
foo()
Without defining y
as a formal parameter in bar()
, I don't think the compiler is OK with it.
But I guess it's totally fine in Python, which is an interpreted language, right?
Is this something different in interpreted language compared to compiled language? What's the actual process Python uses when interpreting the code at top?
EDIT 1: I think the answer below has made this point very clear, it's about free variable and closure. Here are some links which I think help this question a lot:
SO:python-free-variables-why-does-this-fail
SO:closures-in-python
You are looking at a closure; the Python compiler marks
y
inbar
as a free variable becausey
is not assigned to.y
is a local infoo
and because there is a nested scope that uses that name as a free variable,y
is marked as a closure.When the code runs, Python creates a closure for
y
immediately when creating thebar()
function (it is recreated every time you callfoo()
; only the bytecode for the function remains unchanged, a constant attached to thefoo
function code).Only when
bar()
is invoked does Python need to look upy
, which means dereferencing the closure, and from there dereferencing the current value ofy
.You can see all this in action with some introspection and disassembly of the bytecode:
This builds a function with a closure and returns it without calling. This allows us to introspect the
bar()
function created byfoo()
.Note how the Python compiler has inserted a
LOAD_CLOSURE
fory
at the top there.MAKE_CLOSURE
creates the function object with attached closure, forbar
.All
bar()
has to do is dereference the attached closure.The closure points to
y
, and looking up the contents gives you10
, as expected.Compiled languages could do this as well; someone managed to compile Scheme to C, with preserving the closures: Compiling Scheme to C, for example.