Draft PEP (RE: Other situations like this (was RE: [Python-Dev] Nested scopes resolution -- you can breathe again!))

Tim Peters tim.one@home.com
Sun, 25 Feb 2001 17:44:09 -0500


[Tim]
>     Since a module M containing a future_statement naming feature F
>     explicitly requests that the current release act like a
>     future release with respect to F, any code interpreted dynamically
>     from an eval, exec or execfile executed by M will also use the
>     new syntax or semantics associated with F.

[Guido]
> This means that a run-time flag must be available for inspection by
> eval() and execfile(), at least.

eval(), compile() and input() too.  Others?

> I'm not sure that I agree with this for execfile() though -- that's
> often used by mechanisms that emulate module imports, and there it
> would be better if it started off with all features reset to their
> default.

Code emulating module imports is rare.  People writing such mechanisms had
better be experts!  I don't want to warp the normal case to cater to a
handful of deep-magic propeller-heads (they can take care of themselves).

> I'm also not sure about exec and eval() -- it all depends on the
> reason why exec is being invoked.

We're not mind-readers, though.  Best to give a simple (to understand) rule
that caters to normal cases and let the experts worm around the cases where
they didn't mean what they said; e.g., if for some reason they want their
entire module to use nested scopes *except* for execfile, they can move the
execfile into another module and not ask for nested scopes at the top of the
latter, then call the latter from the original module.  But then they're no
longer getting a test of what's going to happen when nested scopes become
The Rule, either.

Note too that this mechanism is intended to be used for more than just the
particular case of nested scopes.  For example, consider changing the
meaning of integer division.  If someone asks for that, then of course they
want

    exec "i = 1/2\n"

or

    eval("1/2")

within the module not to compute 0.

There is no mechanism in the PEP now to make life easier for people who
don't really want what they asked for.  Perhaps there should be.  But if you
believe (as I intended) that the PEP is aimed at making it easier to prepare
code for a future release, all-or-nothing for a module is really the right
behavior.

> Plus, exec and eval() also take a compiled code object, and there it's
> too late to change the future.

That's OK; the PEP *intended* to restrict this to cases where the gimmicks
in question also compile the code from strings.  I'll change that.

> Which leads to the question: should compile() also inherit the future
> settings?

If it doesn't, the module containing it is not going to act like it will in
the MandatoryRelease associated with the __future__ requested.  And in that
case, I don't believe __future__ would be doing its primary job:  it's not
helping me find out how the module *will* act.

> It's certainly a lot easier to implement if exec c.s. are *not*
> affected by the future selection of the invoking environment.  And if
> you *want* it, at least for exec, you can insert the future_statement
> in front of the executed code string.

But not for eval() (see above), or input().

>> Interactive shells may pose special problems.  The intent is that a
>> future_statement typed at an interactive shell prompt affect all code
>> typed to that shell for the remaining life of the shell session.  It's
>> not clear how to achieve that.

> The same flag that I mentioned above can be used here -- basically, we
> can treat each interactive command as an "exec".  Except that this
> time, the command that is the future_statement *does* export its flag
> to the invoking environment.  Plus, I've made a good case against the
> flag. :-(

I think you've pointed out that *sometimes* people may not want what it
does, and that implementing it is harder than not implementing it.  I favor
making the rules as easy as possible for people who want to know how their
module will behave after the feature is mandatory, and believe that
all-or-nothing is clearly a better default.  In either case, changing the
default on a pick-or-choose basis within a single module would require
additional gimmicks not in the current PEP (e.g., maybe more optional flags
to eval() etc; or maybe some new builtin function to toggle it; or maybe
more pseudo-imports; or ...).  I'm not convinced more gimmicks are *needed*,
though, and don't want to see this PEP bloat beyond my original intent for
it.

it's-a-feeble-mechanism-aimed-at-a-specific-goal-ly y'rs  - tim