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
|
||||
Created: 16-Oct-2004
|
||||
Python-Version: 2.5
|
||||
Post-History: 8-Nov-2004, 11-Feb-2006
|
||||
Post-History: 8-Nov-2004, 11-Feb-2006, 12-Feb-2006
|
||||
|
||||
|
||||
Abstract
|
||||
|
@ -142,36 +142,25 @@ The delegation has the form::
|
|||
``run_module`` is only one of a number of functions ``runpy`` exposes to
|
||||
make it easier to run Python code dynamically. The proposed functions
|
||||
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
|
||||
return the resulting module globals dictionary. If supplied, the
|
||||
optional globals dictionary is used as the module globals.
|
||||
Otherwise, a new dictionary is used.
|
||||
return the resulting locals dictionary.
|
||||
|
||||
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
|
||||
automatically initialised with a reference to the top level
|
||||
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).
|
||||
namespace of the ``__builtin__`` module.
|
||||
|
||||
|
||||
``run_module_code(code[, init_globals][, mod_name][, mod_file]\
|
||||
|
@ -186,12 +175,12 @@ documenation).
|
|||
variables below are defined in the supplied dictionary, those
|
||||
definitions are overridden.
|
||||
|
||||
The special global variables ``__name__``, ``__file__``,
|
||||
``__loader__`` and ``__builtins__`` are set in the globals
|
||||
dictionary before the module code is executed. ``__name__``,
|
||||
``__file__``, ``__loader__`` are set based on the optional arguments
|
||||
``mod_name``, ``mod_file`` and ``mod_loader``. If the arguments are
|
||||
omitted, the corresponding special variable is set to ``None``.
|
||||
The special global variables ``__name__``, ``__file__``, and
|
||||
``__loader__`` are set in the globals dictionary before the module
|
||||
code is executed. ``__name__``, ``__file__``, ``__loader__`` are
|
||||
set based on the optional arguments ``mod_name``, ``mod_file`` and
|
||||
``mod_loader``. If the arguments are omitted, the corresponding
|
||||
special variable is set to ``None``.
|
||||
|
||||
If the argument ``as_script`` is supplied and evaluates to ``True``,
|
||||
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
|
||||
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]\
|
||||
[, as_script])``
|
||||
|
||||
|
@ -241,6 +233,9 @@ documenation).
|
|||
level function is ``run_name`` if this optional argument is supplied
|
||||
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])``
|
||||
|
||||
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
|
||||
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
|
||||
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 ``-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
|
||||
source files, compiled files).
|
||||
|
||||
- when using ``exec`` with a separate locals dictionary, name resolution
|
||||
only works right if the code being executed was compiled expecting
|
||||
that the locals dictionary and the globals dictionary were different.
|
||||
Module level code, and anything compiled using ``compile()`` (such as
|
||||
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.
|
||||
- no attempt is made to conceal the quirks of the exec statement when it
|
||||
comes to executing function code objects, or attempting to reference
|
||||
module level names from inside functions when a separate locals
|
||||
dictionary is supplied.
|
||||
|
||||
- The special variables ``__name__``, ``__file__`` and ``__loader__``
|
||||
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
|
||||
information cannot be determined.
|
||||
|
||||
- Lastly, there is no special protection on the as_script argument when
|
||||
file information is not available. This may result in ``sys.srgv[0]``
|
||||
being set to ``None`` if file name information is not available.
|
||||
- Lastly, there is no special protection on the as_script argument.
|
||||
This may result in ``sys.argv[0]`` being set to ``None`` if file
|
||||
name information is not available.
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
==========
|
||||
|
|
Loading…
Reference in New Issue