Search code examples
pythonexectimeit

Why variables inside a function don't get searched in provided global namespace when using timeit or exec function?


As a minimal example, I want to timeit fn function which has a x variable inside. So I passed {'x': 20, 'fn': fn} as my global namespace:

from timeit import timeit

def fn():
    print('This line executed.')
    return x

print(timeit('fn()', globals={'x': 20, 'fn': fn}, number=1_000_000))

I thought that because x is not local, Python checks the global namespace to find it. Then I get back "This line executed." followed by a NameError which says : name 'x' is not defined. But Python sees {'x': 20, 'fn': fn} namespace because when I remove the 'fn': fn part, the error changes to name 'fn' is not defined.

Same is true for exec function(If that helps or has a relationship):

def fn():
    print('This line executed.')
    return x

s = """def fn():
    print('This line executed.')
    return x"""

exec('fn()', {'x': 10, 'fn': fn})

How can I introduce x to these functions? Is it The only option to define them as module-level variables and pass globals() dictionary to global argument?


Solution

  • As document says about globals():

    Return a dictionary representing the current global symbol table. This is always the dictionary of the current module (inside a function or method, this is the module where it is "defined", not the module from which it is called).

    This specifically addressed my issue. So when when Python tries to find x inside fn function, (because it's not local or non-local) it will go and find where it is defind and look at global namespace which the function is defined in, not the global dictionary we provide as a global namespace.

    Although {'x': 20, 'fn': fn} is the global dictionary which Python can find the label fn, but the fn function itself is not defined there, it is only called there.