On Sun, Oct 31, 2021 at 6:36 PM Steven D'Aprano <st...@pearwood.info> wrote:
>
> On Sun, Oct 31, 2021 at 02:24:10PM +1100, Chris Angelico wrote:
>
> > That last part is the most important here: it has to be evaluated *in
> > the context of the function*. That's the only way for things like "def
> > f(a, n=len(a)):" to be possible.
>
> Agreed so far.
>
>
> > Every piece of code in Python is executed, if it is ever executed, in
> > the context that it was written in.
>
> I don't think that's quite right. We can eval() and exec() source code,
> ASTs and code objects in any namespace we have access to, including
> plain old dicts, with some limitations. (E.g. we can't get access to
> other function's namespace, not even if we have their locals() dict. At
> least not in CPython.)

True, I was a bit sloppy with my definitions there; let me try that again.

Every piece of compiled Python code is executed, if it is ever
executed, in a context defined by the location where it was compiled.

With eval/exec, they're compiled in their own dedicated context (at
least, as of Py3 - I don't think I fully understand what Py2 did
there). You can provide a couple of dictionaries to help define that
context, but it's still its own dedicated context.

ASTs don't have contexts yet, but at the point where you compile it
the rest of the way, it gets one. Code objects have their contexts
fully defined.

To my knowledge, there is no way to run code in any context other than
the one it was compiled in, although you can come close by updating a
globals dictionary. You can't get closure references (nonlocals) for
eval/exec, and I don't think it's possible to finish compiling AST to
bytecode in any way that allows you to access more nonlocals.

> In the case of default expressions:
>
>     def func(spam=early_expression, @eggs=late_expression):
>
> early_expression is evaluated in the scope surrounding func (it has to
> be since func doesn't exist yet!) and late_expression needs to be
> evaluated inside func's scope, rather than the scope it was written in.
>

Actually, by the time you're compiling that line of code, func DOES
exist, to some extent. You can't compile a def statement without
simultaneously compiling both its body (the scope of func) and its
surrounding context (whatever that was written in). It's a little
messier now since you can have each of those contexts getting code
added to it, but that's still a limited number of options - for
instance, you can't have a default expression that gets evaluated in
the context of an imported module, nor one that's evaluated in the
*caller's* context.

(I'm aware that I'm using the word "context" here to mean something
that exists at compilation time, and elsewhere I've used the same word
to mean something that only exists at run time. Unfortunately, English
has only so many ways to express the same sorts of concepts, so we end
up reusing. Sorry.)

ChrisA
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/EHJJAS6O7CG2ZRRD6YIIVEHDZR4DO36E/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to