Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How exactly do eval and exec interact with __future__?

Tags:

python

eval

I want to know how __future__ imports interact with eval and exec (and compile, I guess).

Experimentation (with python 2) shows that module-level __future__ imports do have an effect on code executed by eval and exec:

from __future__ import print_function

print(1, end='!\n')
eval(r"print(2, end='!\n')")
exec r"print(3, end='!\n')"

Output:

1!
2!
3!

But at the same time, code executed with exec can perform its own __future__ imports that only affect the code locally:

print 1
exec r"from __future__ import print_function; print(2, end='!\n')"
print 3
exec r"print 4"

Output:

1
2!
3
4

But experimentation can only get you so far. My questions are:

  • Are these interactions well-defined and documented?
  • Is there a way to disable module-level __future__ imports in eval, exec and compile?
like image 347
Aran-Fey Avatar asked Apr 28 '18 09:04

Aran-Fey


1 Answers

Per the language reference:

Code compiled by calls to the built-in functions exec() and compile() that occur in a module M containing a future statement will, by default, use the new syntax or semantics associated with the future statement.

You can disable this behaviour in compile:

The optional arguments flags and dont_inherit control which future statements (see PEP 236) affect the compilation of source.

For example:

>>> from __future__ import print_function
>>> print('foo', 'bar')
foo bar
>>> code1 = compile("print('foo', 'bar')", "<string>", "exec")
>>> exec(code1)
foo bar
>>> code2 = compile("print('foo', 'bar')", "<string>", "exec", dont_inherit=True)
>>> exec(code2)
('foo', 'bar')

The other way around, disabling the usage of __future__ imports in arbitrary code being executed/compiled, is not possible as far as I'm aware.

like image 61
jonrsharpe Avatar answered Oct 19 '22 18:10

jonrsharpe