教科书建议我应该能够做到这一点:
d = {}
exec("C://Users//Dave//Desktop//Bot//bot_config_data.py", globals(), d)
File "<string>", line 1 C://Users//Dave//Desktop//Bot//bot_config_data.py
^
SyntaxError: invalid syntax
我可以这样做:
d = {}
exec('from bot_config_data import price_data', globals(), d)
但是,我想做前者。
我正在尝试编写一个覆盖各种文件的配置数据的方法。
我完全不在这里吗?
更新 这本书很容易让人误解。它发布了部分代码,完整代码块的结果,然后给出了余数。正如我所说的那样,我不是为了覆盖而进行掩护,而是绊倒了自己。
这是我现在的代码:
data = {}
file = 'C:\\Users\\Dave\\Desktop\\Bot\\bot_config_data.py'
with open(file) as f:
code = compile(f.read(), file, "exec")
exec(code, globals(), data)
price_data = data["price_data"]
UPDATE2 使用Mad Physicist的答案,我的代码将是:
from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader
filepath = 'C:\\Users\\Dave\\Desktop\\Bot\\bot_config_data.py'
module_data = os.path.basename(filepath)
spec = spec_from_loader(module_data, SourceFileLoader(module_data, filepath))
bot_config_data = module_from_spec(spec)
spec.loader.exec_module(bot_config_data)
price_data = bot_config_data.price_data
答案 0 :(得分:2)
你完全偏离基础,教科书给你一些非常糟糕的建议。
exec
运行Python代码。与Python语句中一样,不是文件的名称。来自文档:
exec ( object [, globals [, locals ]])
此函数支持Python代码的动态执行。 object 必须是字符串或代码对象。如果是字符串,则将字符串解析为一组Python语句,然后执行(除非发生语法错误)
这就是你的第二个声明正常工作的原因。如果要运行Python模块,请将其导入。如果您需要使用动态名称而不是硬编码的import
语句导入,则可以使用importlib.import_module
:
price_data = importlib.import_module('bot_config_data').price_data
这将为您运行整个导入机制,包括确保bot_config_data
最终在sys.modules
。
如果你真的需要更高级的东西,你可以使用__import__
机器。 __import__
是import
语句的底层实现:
d = {}
bot_config_data = __import__('bot_config_data', locals=d, from_list=['price_data'])
price_data = bot_config_data.price_data
如果您想完全控制该过程,可以使用此处描述的低级机制:How to import a module given the full path?。特别要看我对这个问题的回答,因为它描述了如何将随机文本文件加载为Python脚本:https://stackoverflow.com/a/43602557/2988730:
from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader
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
最后注意事项:您似乎盲目地将路径中的所有\\
转换为//
。正斜杠不需要转义,因此您只需要单个正斜杠。如果您想避免转义反斜杠,请将r
放在字符串前面,使其成为raw string。
答案 1 :(得分:0)
如果您需要使用动态名称而不是硬编码进行导入 import语句,可以使用importlib.import_module:
price_data = importlib.import_module('bot_config_data').price_data
嗯?那个“动态”如何? “ bot_config_data”从字面上是字符串文字。
如果您真的想动态导入模块,这与人们普遍认为的相反,那么唯一的方法就是使用exec()。我挑战任何人来查找或提交用于真正动态导入模块的importlib.import_module或__import__的示例。
要明确:__import__允许动态导入处理,与动态导入不同,因为这是只处理鸡/蛋类型的问题()可以解决。
问题是importlib.import_module()返回一个需要分配的对象。 (它不仅像通常暗示的那样添加到全局名称空间。)但是,您不能在赋值的两侧使用相同的参数。因此,尽管它允许您以更动态的方式处理导入,但它没有提供动态导入模块的方式。