我有一个将 python 脚本文件 (*.py) 存储为字符串的 C# 应用程序。我使用以下方式加载它们:
scriptEngine.CreateScriptSourceFromString(code);
但现在我有多个脚本文件,它们之间存在依赖关系(导入)。为了处理依赖关系,我可以将所有字符串保存回文件夹中的文件并加载我想要执行的脚本:
scriptEngine.CreateScriptSourceFromFile(filePath);
但这会使所有脚本文件可见。有没有办法以内存方式实现这一点,这样脚本文件就不会首先保存到磁盘,而是直接从字符串中加载?
TL;DR:这可能看起来的示例:
myutils.py:
def SomeMethod(p):
print ('SomeMethod(p=%s)' % p)
脚本1.py:
import myutils;
if __name__ == '__main__':
myutils.SomeMethod('script1')
脚本2.py:
import myutils;
if __name__ == '__main__':
myutils.SomeMethod('script2')
我的应用程序将脚本存储为字符串。像
Dictionary<string, string> filePathToContent = new Dictionary<string, string>();
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 中定义(新的导入 Hook )。
meta_path 和path_hooks 两个可以解决需求的python 机制。两者都可以用 Python 或(如果是 IronPython)C#/.NET 实现。鉴于问题涉及从 C# 托管 IronPython,实现导入基础设施可以采用任何一种方式。
使用元路径
IronPython 附带 ResourceMetaPathImporter它允许您拥有一个 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
路径 Hook 包含一个导入器链,用于查询 sys.path
中的所有项目,以确定它们是否可以处理给定路径。类似于 zipimport.cs 的进口商但负责 DLL/EXE 中的嵌入式资源而不是 ZIP 存档。
这可以提供一种更通用的方法,只需将 DLL 添加到路径即可处理其他文件。
使用 PlatformAdaptationLayer
第三种方法的工作原理是提供一个 PlatformAdaptationLayer这是 Microsoft.Scripting
/IronPython 的一部分。 This answer展示了平台适配层解析预定义程序集和包命名空间的嵌入式资源的完整工作示例。
一般说明:相关issue/discussion on github .
关于c# - 存储为字符串的脚本的 IronPython 依赖项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33956131/