Don't try to hide exec's quirks
This commit is contained in:
parent
31438973ae
commit
6a93382b16
116
pep-0338.txt
116
pep-0338.txt
|
@ -8,7 +8,7 @@ Type: Standards Track
|
||||||
Content-Type: text/x-rst
|
Content-Type: text/x-rst
|
||||||
Created: 16-Oct-2004
|
Created: 16-Oct-2004
|
||||||
Python-Version: 2.5
|
Python-Version: 2.5
|
||||||
Post-History: 8-Nov-2004, 11-Feb-2006
|
Post-History: 8-Nov-2004, 11-Feb-2006, 12-Feb-2006
|
||||||
|
|
||||||
|
|
||||||
Abstract
|
Abstract
|
||||||
|
@ -142,36 +142,25 @@ The delegation has the form::
|
||||||
``run_module`` is only one of a number of functions ``runpy`` exposes to
|
``run_module`` is only one of a number of functions ``runpy`` exposes to
|
||||||
make it easier to run Python code dynamically. The proposed functions
|
make it easier to run Python code dynamically. The proposed functions
|
||||||
are listed below (the descriptions are taken from the proposed
|
are listed below (the descriptions are taken from the proposed
|
||||||
documenation).
|
documentation).
|
||||||
|
|
||||||
``run_code(code[, globals])``
|
``run_code(code[, globals][, locals])``
|
||||||
|
|
||||||
Execute the supplied Python code object or string of source code and
|
Execute the supplied Python code object or string of source code and
|
||||||
return the resulting module globals dictionary. If supplied, the
|
return the resulting locals dictionary.
|
||||||
optional globals dictionary is used as the module globals.
|
|
||||||
Otherwise, a new dictionary is used.
|
The optional ``globals`` argument may be used to specify the
|
||||||
|
dictionary to use as the ``globals()`` dictionary when running the
|
||||||
|
code. If the argument is omitted, a new dictionary is used.
|
||||||
|
|
||||||
|
The ``locals`` argument may be used to specify the
|
||||||
|
dictionary to use as the ``locals()`` dictionary when running the
|
||||||
|
code. If it is omitted, the same dictionary is used as is used for
|
||||||
|
``globals()``.
|
||||||
|
|
||||||
The special variable ``__builtins__`` in the globals dictionary is
|
The special variable ``__builtins__`` in the globals dictionary is
|
||||||
automatically initialised with a reference to the top level
|
automatically initialised with a reference to the top level
|
||||||
namespace of the ``__builtin__`` module.
|
namespace of the ``__builtin__`` module.
|
||||||
|
|
||||||
``run_function_code(code[, globals][, locals])``
|
|
||||||
|
|
||||||
Execute the supplied function code object and return a tuple
|
|
||||||
containing the resulting globals and locals dictionaries. If
|
|
||||||
supplied, the optional globals dictionary is used as the module
|
|
||||||
globals. Otherwise, a new dictionary is used. Similarly, if
|
|
||||||
supplied, the optional locals dictionary is used as the function
|
|
||||||
locals. Otherwise, a new dictionary is used.
|
|
||||||
|
|
||||||
As for ``run_code()`` the special variable ``__builtins__`` in the
|
|
||||||
globals dictionary is automatically initialised with a reference to
|
|
||||||
the top level namespace of the ``__builtin__`` module.
|
|
||||||
|
|
||||||
A function code object is required, as module level Python code
|
|
||||||
cannot resolve names correctly when the locals and globals
|
|
||||||
dictionaries are not the same (specifically, new names are bound in
|
|
||||||
the locals dictionary, but this dictionary is not used when looking
|
|
||||||
up references to names at module level from inside a function).
|
|
||||||
|
|
||||||
|
|
||||||
``run_module_code(code[, init_globals][, mod_name][, mod_file]\
|
``run_module_code(code[, init_globals][, mod_name][, mod_file]\
|
||||||
|
@ -186,12 +175,12 @@ documenation).
|
||||||
variables below are defined in the supplied dictionary, those
|
variables below are defined in the supplied dictionary, those
|
||||||
definitions are overridden.
|
definitions are overridden.
|
||||||
|
|
||||||
The special global variables ``__name__``, ``__file__``,
|
The special global variables ``__name__``, ``__file__``, and
|
||||||
``__loader__`` and ``__builtins__`` are set in the globals
|
``__loader__`` are set in the globals dictionary before the module
|
||||||
dictionary before the module code is executed. ``__name__``,
|
code is executed. ``__name__``, ``__file__``, ``__loader__`` are
|
||||||
``__file__``, ``__loader__`` are set based on the optional arguments
|
set based on the optional arguments ``mod_name``, ``mod_file`` and
|
||||||
``mod_name``, ``mod_file`` and ``mod_loader``. If the arguments are
|
``mod_loader``. If the arguments are omitted, the corresponding
|
||||||
omitted, the corresponding special variable is set to ``None``.
|
special variable is set to ``None``.
|
||||||
|
|
||||||
If the argument ``as_script`` is supplied and evaluates to ``True``,
|
If the argument ``as_script`` is supplied and evaluates to ``True``,
|
||||||
then ``sys.argv[0]`` is updated with the value of ``mod_file``
|
then ``sys.argv[0]`` is updated with the value of ``mod_file``
|
||||||
|
@ -229,6 +218,9 @@ documenation).
|
||||||
level function is ``run_name`` if this optional argument is supplied
|
level function is ``run_name`` if this optional argument is supplied
|
||||||
and ``None`` otherwise.
|
and ``None`` otherwise.
|
||||||
|
|
||||||
|
The ``mod_loader`` argument to the lower level function is set to
|
||||||
|
``None`` and the ``mod_file`` argument is set to ``filename``.
|
||||||
|
|
||||||
``run_compiled_file(filename[, init_globals][, run_name]\
|
``run_compiled_file(filename[, init_globals][, run_name]\
|
||||||
[, as_script])``
|
[, as_script])``
|
||||||
|
|
||||||
|
@ -241,6 +233,9 @@ documenation).
|
||||||
level function is ``run_name`` if this optional argument is supplied
|
level function is ``run_name`` if this optional argument is supplied
|
||||||
and ``None`` otherwise.
|
and ``None`` otherwise.
|
||||||
|
|
||||||
|
The ``mod_loader`` argument to the lower level function is set to
|
||||||
|
``None`` and the ``mod_file`` argument is set to ``filename``.
|
||||||
|
|
||||||
``run_file(filename[, init_globals][, run_name][, as_script])``
|
``run_file(filename[, init_globals][, run_name][, as_script])``
|
||||||
|
|
||||||
Execute the specified Python file and return the resulting module
|
Execute the specified Python file and return the resulting module
|
||||||
|
@ -257,6 +252,9 @@ documenation).
|
||||||
level function is ``run_name`` if this optional argument is supplied
|
level function is ``run_name`` if this optional argument is supplied
|
||||||
and ``None`` otherwise.
|
and ``None`` otherwise.
|
||||||
|
|
||||||
|
The ``mod_loader`` argument to the lower level function is set to
|
||||||
|
``None`` and the ``mod_file`` argument is set to ``filename``.
|
||||||
|
|
||||||
|
|
||||||
When invoked as a script, the ``runpy`` module finds and executes the
|
When invoked as a script, the ``runpy`` module finds and executes the
|
||||||
module supplied as the first argument. It adjusts ``sys.argv`` by
|
module supplied as the first argument. It adjusts ``sys.argv`` by
|
||||||
|
@ -272,46 +270,14 @@ There were some key design decisions that influenced the development of
|
||||||
the ``runpy`` module. These are listed below.
|
the ``runpy`` module. These are listed below.
|
||||||
|
|
||||||
- the ``-m`` switch really only needs the ``run_module`` function. The
|
- the ``-m`` switch really only needs the ``run_module`` function. The
|
||||||
other six functions are included to give the module API coverage
|
other five functions are included to give the module API coverage
|
||||||
of the other sources of executable Python code (strings, code objects
|
of the other sources of executable Python code (strings, code objects
|
||||||
source files, compiled files).
|
source files, compiled files).
|
||||||
|
|
||||||
- when using ``exec`` with a separate locals dictionary, name resolution
|
- no attempt is made to conceal the quirks of the exec statement when it
|
||||||
only works right if the code being executed was compiled expecting
|
comes to executing function code objects, or attempting to reference
|
||||||
that the locals dictionary and the globals dictionary were different.
|
module level names from inside functions when a separate locals
|
||||||
Module level code, and anything compiled using ``compile()`` (such as
|
dictionary is supplied.
|
||||||
a source string passed to ``exec``) assumes that the two dictionaries
|
|
||||||
are the same. If they're different, references to globals from inside
|
|
||||||
functions aren't resolved using the locals dictionary::
|
|
||||||
|
|
||||||
>>> code = """
|
|
||||||
... x = 1
|
|
||||||
... print x
|
|
||||||
... def f():
|
|
||||||
... print "Try to resolve x from inside a function"
|
|
||||||
... print x
|
|
||||||
... f()
|
|
||||||
... """
|
|
||||||
>>> exec code
|
|
||||||
1
|
|
||||||
Try to resolve x from inside a function
|
|
||||||
1
|
|
||||||
>>> exec code in {}
|
|
||||||
1
|
|
||||||
Try to resolve x from inside a function
|
|
||||||
1
|
|
||||||
>>> exec code in {}, {}
|
|
||||||
1
|
|
||||||
Try to resolve x from inside a function
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "<stdin>", line 1, in <module>
|
|
||||||
File "<string>", line 7, in <module>
|
|
||||||
File "<string>", line 6, in f
|
|
||||||
NameError: global name 'x' is not defined
|
|
||||||
|
|
||||||
Accordingly, the basic ``run_code`` function doesn't accept a locals
|
|
||||||
dictionary, and the ``run_function_code`` function checks that the
|
|
||||||
supplied code object expects locals and globals to be different.
|
|
||||||
|
|
||||||
- The special variables ``__name__``, ``__file__`` and ``__loader__``
|
- The special variables ``__name__``, ``__file__`` and ``__loader__``
|
||||||
are set in a module's global namespace before the module is executed.
|
are set in a module's global namespace before the module is executed.
|
||||||
|
@ -325,9 +291,9 @@ the ``runpy`` module. These are listed below.
|
||||||
these variables are simply set to ``None`` when the relevant
|
these variables are simply set to ``None`` when the relevant
|
||||||
information cannot be determined.
|
information cannot be determined.
|
||||||
|
|
||||||
- Lastly, there is no special protection on the as_script argument when
|
- Lastly, there is no special protection on the as_script argument.
|
||||||
file information is not available. This may result in ``sys.srgv[0]``
|
This may result in ``sys.argv[0]`` being set to ``None`` if file
|
||||||
being set to ``None`` if file name information is not available.
|
name information is not available.
|
||||||
|
|
||||||
|
|
||||||
Alternatives
|
Alternatives
|
||||||
|
@ -345,6 +311,12 @@ Both approaches were rejected as they do not meet the main goal of the
|
||||||
``-m`` switch -- to allow the full Python namespace to be used to
|
``-m`` switch -- to allow the full Python namespace to be used to
|
||||||
locate modules for execution from the command line.
|
locate modules for execution from the command line.
|
||||||
|
|
||||||
|
An earlier version of this PEP included some mistaken assumption
|
||||||
|
about the way ``exec`` handled locals dictionaries and code from
|
||||||
|
function objects. These mistaken assumptions led to some unneeded
|
||||||
|
design complexity which has now been removed - ``run_code`` shares all
|
||||||
|
of the quirks of ``exec``.
|
||||||
|
|
||||||
|
|
||||||
References
|
References
|
||||||
==========
|
==========
|
||||||
|
|
Loading…
Reference in New Issue