Hyppää sisältöön

Ei vielä käännetty

Tätä sivua ei ole vielä käännetty suomeksi, joten se näytetään englanniksi. Auta kääntämään

eval() Function Complexity

The eval() function evaluates one Python expression and returns its value. Given a string, it compiles the string first, on every call: nothing is cached. Given a code object from compile(), it skips compilation and only runs the code.

n is the length of the source: characters in a str, bytes in a bytes. v is the local variables in the function that calls eval(). The expression's own cost - the calls it makes, the objects it builds - belongs to the expression and is added to every bound below.

Complexity Reference

eval()

Operation Time Space Notes
eval(source) with a str or bytes source O(n) + the expression's cost O(n) + the expression's cost Compiles on every call; leading spaces and tabs are skipped
eval(code) with a code object The expression's cost The expression's cost No compilation. Code compiled in 'exec' mode runs and returns None; code with free variables raises TypeError
eval(source, globals) O(1) more O(1) more globals must be a dict; __builtins__ is added to it if missing, and locals defaults to it
eval(source, globals, locals) O(1) more O(1) more locals may be any mapping
eval(source) or eval(code) inside a function, without globals O(v²) more on 3.13+, O(v) more on 3.11 and 3.12 O(v) more Copies the function's local variables into a dict on every call; passing globals skips the copy
Invalid source O(n) O(n) Raises SyntaxError, for a statement or an empty string too; an undefined name raises NameError only when evaluated

Compile Once, Evaluate Many Times

eval() given a string compiles it every time. Compiling it once and passing the code object leaves only the evaluation. An audit hook shows each compilation as it happens.

import sys

compiled = []
sys.addaudithook(lambda event, args: compiled.append(args[1]) if event == "compile" else None)

x = 3
for _ in range(100):
    assert eval("x ** 2") == 9  # O(n) per call - compiles the string each time
assert compiled.count("<string>") == 100

code = compile("x ** 2", "<expr>", "eval")  # O(n), once
for _ in range(100):
    assert eval(code) == 9  # no compilation, only the expression runs
assert compiled.count("<expr>") == 1

Namespaces

Without arguments, eval() uses the caller's globals and locals. globals must be a real dict; if it has no __builtins__ key, eval() adds one, so builtins stay reachable. locals may be any mapping, and defaults to globals when only globals is given.

import collections

namespace = {"x": 10, "y": 20}
assert eval("x + y", namespace) == 30  # O(n)
assert "__builtins__" in namespace  # added on first use
assert eval("len('abc')", {}) == 3  # builtins are reachable from an empty dict

layers = collections.ChainMap({"a": 1}, {"b": 2})
assert eval("a + b", {}, layers) == 3  # locals may be any mapping

try:
    eval("a", layers)
except TypeError as error:
    assert "dict" in str(error)
else:
    raise AssertionError("a ChainMap was accepted as globals")

Inside a Function

Called in a function with no namespaces, eval() first copies the function's local variables into a dict, on every call. That is O(v) on 3.11 and 3.12 and O(v²) on 3.13+. Passing a dict as globals skips the copy, which matters in a loop inside a function with many locals.

def scaled(values, factor):
    results = []
    for value in values:
        results.append(eval("value * factor"))  # copies the locals, then O(n)
    return results

assert scaled([1, 2, 3], 10) == [10, 20, 30]

def scaled_with_namespace(values, factor):
    code = compile("value * factor", "<expr>", "eval")  # O(n), once
    namespace = {"factor": factor}
    results = []
    for value in values:
        namespace["value"] = value  # O(1)
        results.append(eval(code, namespace))  # no copy, no compilation
    return results

assert scaled_with_namespace([1, 2, 3], 10) == [10, 20, 30]

Expressions Only

eval() takes one expression. A statement, or an empty string, is a SyntaxError; use exec() for statements. A code object compiled in 'exec' mode is the exception: it runs, and eval() returns None.

try:
    eval("x = 5")
except SyntaxError:
    pass
else:
    raise AssertionError("eval() ran an assignment")

try:
    eval("")
except SyntaxError:
    pass
else:
    raise AssertionError("eval() accepted an empty string")

namespace = {}
assert eval(compile("x = 5", "<string>", "exec"), namespace) is None
assert namespace["x"] == 5

assert eval("  1 + 1") == 2  # leading spaces and tabs are skipped

Safer Alternatives

eval() runs whatever the expression does, and an empty or restricted __builtins__ does not make it safe. For untrusted text that should hold a value, ast.literal_eval() parses it in O(n) and builds only literal values; an expression such as __import__('os') raises ValueError.

import ast

assert ast.literal_eval("[1, 2, 3]") == [1, 2, 3]  # O(n)
assert ast.literal_eval("{'a': 1, 'b': 2}") == {"a": 1, "b": 2}

try:
    ast.literal_eval("__import__('os')")
except ValueError as error:
    assert "malformed" in str(error)
else:
    raise AssertionError("literal_eval() made a call")

Common Patterns

Evaluating a Formula per Record

formula = compile("price * quantity * (1 - discount)", "<formula>", "eval")  # O(n), once

orders = [
    {"price": 10.0, "quantity": 3, "discount": 0.0},
    {"price": 4.0, "quantity": 5, "discount": 0.5},
]
totals = [eval(formula, {"__builtins__": {}}, order) for order in orders]  # no compilation
assert totals == [30.0, 10.0]

Performance Best Practices

✅ Do:

  • Compile an expression once with compile() and pass the code object when it is evaluated repeatedly
  • Pass a namespace dict when calling eval() in a loop inside a function, so the locals are not copied on every call
  • Use ast.literal_eval() for text that should only hold a value

❌ Avoid:

  • Calling eval() on a string inside a loop - it compiles the string every time
  • Calling eval() on untrusted input, even with restricted globals
  • Building code as strings for eval() where a function, a lambda or a dict lookup would do

Version Notes

  • Python 3.13+: globals and locals can be passed as keyword arguments
  • Python 3.13+: Inside a function without namespaces, copying the locals costs O(v²) per call; it is O(v) on 3.11 and 3.12
  • All Python 3: eval() runs arbitrary code; never pass it untrusted input