Question:
Why `import` does not work in this case (in `exec`)?

Problem:

Sorry but the situation a bit complicated that I can't describe it clearly in the title.


So this is the script to be imported later in exec:

# script_to_be_imported.py


def f():

    print("Hello World!")


And this is my main script:

# main.py


script = """

import script_to_be_imported

def function_to_use_the_imported_script():

    script_to_be_imported.f()


function_to_use_the_imported_script()

"""



def function_invokes_exec():

    exec(script)



function_invokes_exec()


I am using Python 3.11.4 (tags/v3.11.4:d2340ef, Jun  7 2023, 05:45:37) [MSC v.1934 64 bit (AMD64)] on win32, and it tells me that:

Traceback (most recent call last):

  File "C:\Users\yueyinqiu\Documents\MyTemporaryFiles\stackoverflow\importInExec\main.py", line 16, in <module>

    function_invokes_exec()

  File "C:\Users\yueyinqiu\Documents\MyTemporaryFiles\stackoverflow\importInExec\main.py", line 13, in function_invokes_exec

    exec(script)

  File "<string>", line 6, in <module>

  File "<string>", line 4, in function_to_use_the_imported_script

NameError: name 'script_to_be_imported' is not defined


But when I make some small changes which I think they are unrelated, it could work correctly.


For example, it works when exec is invoked outside the function:


# main.py


script = """

import script_to_be_imported

def function_to_use_the_imported_script():

    script_to_be_imported.f()


function_to_use_the_imported_script()

"""


exec(script)


and also works when:

# main.py


script = """

import script_to_be_imported

script_to_be_imported.f()

"""



def function_invokes_exec():

    exec(script)



function_invokes_exec()


It even works when a value is passed to global although it's just an empty dictionary:

# main.py


script = """

import script_to_be_imported

def function_to_use_the_imported_script():

    script_to_be_imported.f()


function_to_use_the_imported_script()

"""



def function_invokes_exec():

    exec(script, {})



function_invokes_exec()


So have I misunderstood something? Or it is a bug of python?


Solution:

From >documentation:


...if the optional parts are omitted, the code is executed in the "current scope".


The current scope here is the local namespace of the function_invokes_exec function.

If you look closely, the error comes from this line script_to_be_imported.f() inside function_to_use_the_imported_script function.

before function_to_use_the_imported_script gets called, what we have in the local scope of function_invokes_exec?

  1. script_to_be_imported

  2. function_to_use_the_imported_script

Now when function_to_use_the_imported_script gets called and encounters a name, it should either look at "its" local namespace or global module(forget about nonlocal namespace for now). script_to_be_imported is not in its local, is it inside the global namespace? No! So it can't find it. Where is it? It's in function_invokes_exec's local namespace. Does function_to_use_the_imported_script have access to that namespace? No.

Beside your mentioned cases, if you import script_to_be_imported in the global namespace it would also work:

# main.py

import script_to_be_imported


script = """

def function_to_use_the_imported_script():

    script_to_be_imported.f()


function_to_use_the_imported_script()

"""


def function_invokes_exec():

    exec(script)


function_invokes_exec()



Suggested blogs:

>Can not run phpstan under docker with memory lack error

>Attempt to read property "data_audit" on array laravel view loop foreach

>How to use start and limit on DataTables in Laravel for mobile API?

>Login to Laravel API- Laravel

>Make Xdebug stop at breakpoints in PhpStorm using Docker

>Creating a service in Laravel using app(FQCN)


Adequate Infosoft

Adequate Infosoft

Submit
0 Answers