存储为字符串的脚本的IronPython依赖项
我有一个C#应用程序,它将python脚本文件(* .py)存储为字符串。 我用它们加载它们:
scriptEngine.CreateScriptSourceFromString(code);
但是现在我有多个脚本文件,它们之间有依赖关系(导入)。 为了处理依赖项,我可以将所有字符串保存回文件夹中的文件并加载我想要执行的脚本:
scriptEngine.CreateScriptSourceFromFile(filePath);
但这会使所有脚本文件都可见。 有没有办法以内存方式实现这一点,以便脚本文件不首先保存到磁盘,而是直接从字符串加载?
TL; DR:这看起来如何:
myutils.py:
def SomeMethod(p): print ('SomeMethod(p=%s)' % p)
script1.py:
import myutils; if __name__ == '__main__': myutils.SomeMethod('script1')
script2.py:
import myutils; if __name__ == '__main__': myutils.SomeMethod('script2')
我的应用程序将脚本存储为字符串。 就像是
Dictionary filePathToContent = new Dictionary(); filePathToContent["myutils.py"] = "..."; // The script file content. filePathToContent["script1.py"] = "..."; // The script file content. filePathToContent["script2.py"] = "..."; // The script file content.
我想调用script1.py而不必先将脚本保存到文件夹中。 注意:代码只是我所拥有的简化示例。
一般来说,IronPython和Python中有几种自定义导入处理方法。 大多数概念在PEP 0302 (新导入挂钩)中定义。
可以解决需求的两个python机制是meta_path和path_hooks 。 两者都可以用Python或(在IronPython的情况下)C#/ .NET实现。 鉴于问题涉及从C#托管IronPython实现导入基础架构可以以任何方式工作。
使用meta_path
IronPython随附ResourceMetaPathImporter ,它允许您将包含脚本的ZIP存档作为嵌入式资源。 假设这样的存档被称为当前正在执行的程序scripts.zip
包含的scripts.zip
,则所需的设置可能如下所示:
var engine = Python.CreateEngine(); var sysScope = engine.GetSysModule(); List metaPath = sysScope.GetVariable("meta_path"); var importer = new ResourceMetaPathImporter(Assembly.GetExecutingAssembly(), "scripts.zip"); metaPath.Add(importer); sysScope.SetVariable("meta_path", metaPath);
如果已知组件和脚本并且ZIP打包不会干扰开发过程,则此方法很有效。
使用path_hooks
路径挂钩包含一系列导入程序,这些导入程序将查询sys.path
中的所有项目,以确定它们是否可以处理给定路径。 类似于zipimport.cs的导入程序,但负责DLL / EXE中的嵌入资源而不是ZIP存档。 这可以提供一种更通用的方法,通过仅向路径添加DLL来处理其他文件。
使用PlatformAdaptationLayer
第三种方法是提供PlatformAdaptationLayer ,它是Microsoft.Scripting
/ IronPython的一部分。 此答案显示了平台自适应层的完整工作示例,该层解析了预定义程序集和程序包命名空间的嵌入资源。
一般说明: 关于github的相关问题/讨论 。
您可以将不同的脚本创建为一个函数,并根据给定的参数调用这些函数
ScriptScope scope = scriptEngine.CreateScope(); scope.SetVariable("language", "en"); scriptEngine.Execute(scope);
和python(我知道的愚蠢的例子):
def doEnStuff(): print "english" def doEsStuff(): print "espagna" if language == "en" doEnStuff()