Skip to content Skip to sidebar Skip to footer

Using Exec To Load Module Variables, Using A File Path

A textbook suggests I should be able to do this: d = {} exec('C://Users//Dave//Desktop//Bot//bot_config_data.py', globals(), d) File '', line 1 C://Users//Dave//Des

Solution 1:

You are completely off-base and the textbook is giving you some very bad advice.

exec runs Python code. As in Python statements, not the name of a file. From the docs:

exec(object[, globals[, locals]])

This function supports dynamic execution of Python code. object must be either a string or a code object. If it is a string, the string is parsed as a suite of Python statements which is then executed (unless a syntax error occurs)

That is why your second statement works fine. If you want to run a Python module, import it. If you need to import using a dynamic name instead of a hard-coded import statement, you can use importlib.import_module:

price_data = importlib.import_module('bot_config_data').price_data

This will run the whole import machinery for you, including ensuring that bot_config_data ends up in sys.modules.

If you really need something even fancier, you can use the __import__ machinery. __import__ is the under-the-hood implementation of the import statement:

d = {}
bot_config_data = __import__('bot_config_data', locals=d, from_list=['price_data'])
price_data = bot_config_data.price_data

If you want full control over the process, you can use the low-level machinery described here: How to import a module given the full path?. In particular see my answer to that question, since it describes how to load random text files as Python scripts: https://stackoverflow.com/a/43602557/2988730:

from importlib.utilimport spec_from_loader, module_from_spec
from importlib.machineryimportSourceFileLoader 

spec = spec_from_loader("bot_config_data", SourceFileLoader("bot_config_data", "C:/Users/Dave/Desktop/Bot/bot_config_data.py"))
bot_config_data = module_from_spec(spec)
spec.loader.exec_module(bot_config_data)
price_data = bot_config_data.price_data

Final note: It looks like you blindly converted all the \\ to // in your path. Forward slashes do not need to be escaped, so you only need single forward slashes. If you want to avoid escaping your backslashes, put r in front of your string to make it a raw string.

Solution 2:

If you need to import using a dynamic name instead of a hard-coded import statement, you can use importlib.import_module:

price_data = importlib.import_module('bot_config_data').price_data

Huh? How is that "dynamic"? 'bot_config_data' is literally a string literal.

If you really want to import modules dynamically, contrary to what is widely believed, the only way to do this is with exec(). I challenge anyone to find or submit an example of importlib.import_module or __import__ being used to truly dynamically import modules.

To be clear: __import__ allows for the dynamic handling of imports, which is not the same as dynamically importing, as that is a chicken/egg type problem only exec() can solve.

The problem is that importlib.import_module() returns an object, which needs an assignment. (It doesn't just add to the global namespace as is often implied.) But you can't use the same argument on both sides of the assignment. So while it allows you to do handle imports in a more dynamic way, it provides no way of dynamically importing modules.

Post a Comment for "Using Exec To Load Module Variables, Using A File Path"