PEP thought experiment: Unix style exec for function/method calls
Michael
ms at cerenity.org
Sun Jul 2 06:49:01 EDT 2006
Carl Banks wrote:
> Maybe look to see how tail-recursive optimization in languages such as
> Scheme work, and whether it can be generalized.
Thanks for the feedback - I should've remembered tail recursion.
> I doubt this would be possible without a major change in how functions
> work in Python. The most obvious problem is that functions refer to
> local variables by an index, not by name. If you were to execute the
> bytecode of one function in the stack frame of another, Bad Things
> would happen.
Oh that's a pity. I can see why you'd do that, but it is a pity. That would
tend to imply that _replacing_ rather than _reusing_ the top frame is the
most doable/likely/sensible approach. (It's also very obviously easier to
emulate)
(And yes, I was consider reusing or replacing *only* the top stack frame.
Replacing seems better with retrospect, even if reusing seemed like a fun
idea :-)
> > def set_name():
> > name = raw_input("Enter your name! > ")
> > cexe greet()
> >
> > def greet():
> > print "hello", name
> >
> > cexe set_name()
> > print "We don't reach here"
> > ----------
> >
> > This would execute, ask for the user's name, say hello to them and then
> > exit - not reaching the final print "We don't reach here" statement.
>
> Only if you were to replace the whole stack. If you only replace or
> reuse the top frame, I would think greet would exit and execution would
> resume right after the point from which set_name was called. Or am I
> misunderstanding what you want?
I think you are.
In the hypothetical example, your code by definition gets called by
something. This leave a hypothetical return point. For the moment, lets
make things clearer by what I mean by changing the example to this:
> > 1 def set_name():
> > 2 name = raw_input("Enter your name! > ")
> > 3 cexe greet()
> > 4
> > 5 def greet():
> > 6 print "hello", name
> > 7
> > 8 def main():
> > 9 cexe set_name()
> > 10 print "We don't reach here"
> > 11
> > 12 main()
> > 13 print "see what I mean?"
> > ----------
at line 12, we call 8. We can argue then our stack looks like this:
[ { "context" : "main", pc : 8 }, { "context" : "__main__", pc : 12 }, ]
(I'm going to push/pop at the front of the list)
We reach line 9, before we execute the code there:
[ { "context" : "main", pc : 9 }, { "context" : "__main__", pc : 12 }, ]
After we execute, it does a cexe call of set_name, not a normal call of
set_name. This causes the top stack frame to be _replaced_ :
[ { "context" : "set_name", pc : 1 }, { "context" : "__main__", pc : 12 }, ]
We then carry on, until we reach line 3, at which point before execution our
stack would look something like:
[ { "context" : "set_name", pc : 3 }, { "context" : "__main__", pc : 12 }, ]
And after:
[ { "context" : "greet", pc : 5 }, { "context" : "__main__", pc : 12 }, ]
We'd then execute line 6, and after executing that line, our stack would
look like this:
[ { "context" : "greet", pc : 6 }, { "context" : "__main__", pc : 12 }, ]
We're falling off the end of a function at that point, so we'd pop the top
stack frame, as follows:
[ { "context" : "__main__", pc : 12 }, ]
Which means we return to the line after 12, and continue on with line 13
print "see what I mean". That means the '''print "We don't reach here"'''
code isn't executed.
>> * Am I mad? :)
>
> Yep. :)
Thought so!
Thanks :-)
Michael.
More information about the Python-list
mailing list