From 325330b0ead67c1179dd8fc089c01931796e29b8 Mon Sep 17 00:00:00 2001 From: slateny <46876382+slateny@users.noreply.github.com> Date: Mon, 5 Dec 2022 01:10:21 -0800 Subject: [PATCH 1/4] Improve documentation of eval() --- Doc/library/functions.rst | 73 +++++++++++++++++++++++-------------- Doc/reference/datamodel.rst | 2 + 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 110e7e5d7fb9a7..45689150908862 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -514,44 +514,40 @@ are always available. They are listed here in alphabetical order. .. function:: eval(expression, /, globals=None, locals=None) - The arguments are a string and optional globals and locals. If provided, + This function dynamically evaluates Python expressions. The first argument can + be a string or a :ref:`code object `. The optional + arguments specify the global and local namespaces respectively. If provided, *globals* must be a dictionary. If provided, *locals* can be any mapping object. - The *expression* argument is parsed and evaluated as a Python expression - (technically speaking, a condition list) using the *globals* and *locals* - dictionaries as global and local namespace. If the *globals* dictionary is - present and does not contain a value for the key ``__builtins__``, a - reference to the dictionary of the built-in module :mod:`builtins` is - inserted under that key before *expression* is parsed. That way you can - control what builtins are available to the executed code by inserting your - own ``__builtins__`` dictionary into *globals* before passing it to - :func:`eval`. If the *locals* dictionary is omitted it defaults to the - *globals* dictionary. If both dictionaries are omitted, the expression is - executed with the *globals* and *locals* in the environment where - :func:`eval` is called. Note, *eval()* does not have access to the - :term:`nested scopes ` (non-locals) in the enclosing - environment. + When the *expression* argument is a string, it is parsed and evaluated as a + Python expression (see :ref:`expression-input`). The leading and trailing spaces, + tabs, and newlines are stripped. + + The evaluation is performed in the environment specified by the arguments + *globals* and *locals*. If both are omitted, by default it uses the + environment where :func:`eval` is called. If only the *globals* argument is + provided, the local namespace defaults to *globals*. + + Before evaluation, the special key ``"__builtins__"`` is searched for in the + global namespace that is explicitly or implicitly specified. + If this key is not present, a reference to the dictionary of the + built-in module :mod:`builtins` is inserted *in-place* under that key, so + that built-in identifiers resolve to their usual built-in implementations. + By overriding the value for the key ``"__builtins__"`` in *globals*, you + can control what builtins are available to the expression being evaluated. The return value is the result of - the evaluated expression. Syntax errors are reported as exceptions. Example: + the evaluated expression. Syntax errors are reported as exceptions. For example: >>> x = 1 >>> eval('x+1') 2 This function can also be used to execute arbitrary code objects (such as - those created by :func:`compile`). In this case, pass a code object instead - of a string. If the code object has been compiled with ``'exec'`` as the - *mode* argument, :func:`eval`\'s return value will be ``None``. - - Hints: dynamic execution of statements is supported by the :func:`exec` - function. The :func:`globals` and :func:`locals` functions - return the current global and local dictionary, respectively, which may be - useful to pass around for use by :func:`eval` or :func:`exec`. - - If the given source is a string, then leading and trailing spaces and tabs - are stripped. + those created by :func:`compile`). In this case, *expression* will be + a code object instead of a string. If the code object has been compiled with + ``'exec'`` as the *mode* argument, the return value will be ``None``. See :func:`ast.literal_eval` for a function that can safely evaluate strings with expressions containing only literals. @@ -561,6 +557,29 @@ are always available. They are listed here in alphabetical order. Raises an :ref:`auditing event ` ``exec`` with the code object as the argument. Code compilation events may also be raised. + .. note:: + + Dynamic evaluation at run-time is not equivalent to embedding the + expression at the same place in a Python program and having it compiled + as a part of the whole program; see :ref:`dynamic-features` for details. + + In particular, :func:`eval` does not have access to the :term:`nested + scopes ` (non-locals) in the enclosing environment. Of + note are expressions such as :term:`lambdas `, + :ref:`comprehensions `, and :term:`generator expressions + `, which create an inner scope of their own. + The action of an assignment expression (see :pep:`572`) also + depends on scope information determined at compile-time. + + Interaction between these expressions and :func:`eval` can be explicitly + controlled by the arguments *globals* and *locals* in the aforementioned manner. + The built-in functions :func:`globals` and :func:`locals` return the + current global and local dictionaries respectively, which may be useful + for constructing namespaces for these arguments. + + Dynamic execution of *statements* is supported by the :func:`exec` + function (see below). + .. index:: builtin: exec .. function:: exec(object, globals=None, locals=None, /, *, closure=None) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index fd682fcff02003..ace6e164325b7f 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -943,6 +943,8 @@ Internal types .. index:: bytecode, object; code, code object + .. _datamodel-codeobjects: + Code objects Code objects represent *byte-compiled* executable Python code, or :term:`bytecode`. The difference between a code object and a function object is that the function From 52538bf732eb7dd1c4f14b5fb91b21a1ed1b6c70 Mon Sep 17 00:00:00 2001 From: slateny <46876382+slateny@users.noreply.github.com> Date: Mon, 5 Dec 2022 02:28:16 -0800 Subject: [PATCH 2/4] Remove trailing space --- Doc/library/functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 45689150908862..c4ef1c11829490 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -579,7 +579,7 @@ are always available. They are listed here in alphabetical order. Dynamic execution of *statements* is supported by the :func:`exec` function (see below). - + .. index:: builtin: exec .. function:: exec(object, globals=None, locals=None, /, *, closure=None) From e7244d91588e03a443426bb17ccf22185d610bd7 Mon Sep 17 00:00:00 2001 From: slateny <46876382+slateny@users.noreply.github.com> Date: Mon, 5 Dec 2022 02:30:58 -0800 Subject: [PATCH 3/4] Remove hyphen per review --- Doc/library/functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index c4ef1c11829490..9abfb9d3c88883 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -569,7 +569,7 @@ are always available. They are listed here in alphabetical order. :ref:`comprehensions `, and :term:`generator expressions `, which create an inner scope of their own. The action of an assignment expression (see :pep:`572`) also - depends on scope information determined at compile-time. + depends on scope information determined at compile time. Interaction between these expressions and :func:`eval` can be explicitly controlled by the arguments *globals* and *locals* in the aforementioned manner. From 3c90d9c22c3706a8ea128f6e3a83365f7b401212 Mon Sep 17 00:00:00 2001 From: Stanley <46876382+slateny@users.noreply.github.com> Date: Wed, 7 Dec 2022 23:28:24 -0800 Subject: [PATCH 4/4] The -> Any Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Doc/library/functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 9abfb9d3c88883..65602cb030c13a 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -521,7 +521,7 @@ are always available. They are listed here in alphabetical order. object. When the *expression* argument is a string, it is parsed and evaluated as a - Python expression (see :ref:`expression-input`). The leading and trailing spaces, + Python expression (see :ref:`expression-input`). Any leading and trailing spaces, tabs, and newlines are stripped. The evaluation is performed in the environment specified by the arguments