使用IronPython进行无限递归引用

时间:2014-01-02 20:08:09

标签: c# python recursion ironpython

如果这是一个愚蠢的问题,请提前抱歉。我是Python的新手(根本不是其他语言的新手),特别是IronPython的新手。

我正在尝试通过我的C#项目运行Python项目。我将所有相关的Python源代码都包含在嵌入式资源中(我将其读入Dictionary<string,string>,其中键是模块的名称,值是文件的内容。

我已经实现了一个类似于“Custom IronPython import resolution”回复中建议的类,如下所示:

public class PythonInstance
{
    private ScriptEngine engine;
    private ScriptScope scope;
    private ScriptSource source;
    private CompiledCode compiled;
    private object pythonClass;
    private delegate object ImportDelegate(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple tuple);
    private Dictionary<string, string> importModulesCode = new Dictionary<string, string>();

    public PythonInstance(string code, Dictionary<string,string> modulesCode, string className = "PyClass")
    {
        this.importModulesCode.Clear();
        foreach(KeyValuePair<string,string> module in modulesCode)
            this.importModulesCode.Add(module.Key, module.Value);

        //creating engine and stuff
        this.engine = Python.CreateEngine();
        this.scope = Python.GetBuiltinModule(engine);//engine.CreateScope();

        this.scope.SetVariable("__import__", new ImportDelegate(this.ImportModuleFromResources));

        //loading and compiling code
        this.source = this.engine.CreateScriptSourceFromString(code, SourceCodeKind.Statements);
        this.compiled = this.source.Compile();

        //now executing this code (the code should contain a class)
        this.compiled.Execute(this.scope);

        //now creating an object that could be used to access the stuff inside a python script
        this.pythonClass = this.engine.Operations.Invoke(this.scope.GetVariable(className));
    }

    public void SetVariable(string variable, dynamic value)
    {
        this.scope.SetVariable(variable, value);
    }

    public dynamic GetVariable(string variable)
    {
        return this.scope.GetVariable(variable);
    }

    public void CallMethod(string method, params dynamic[] arguments)
    {
        this.engine.Operations.InvokeMember(this.pythonClass, method, arguments);
    }

    public dynamic CallFunction(string method, params dynamic[] arguments)
    {
        return this.engine.Operations.InvokeMember(this.pythonClass, method, arguments);
    }

    protected object ImportModuleFromResources(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple tuple)
    {
        if ((this.importModulesCode.Keys.Contains(moduleName)) && (!string.IsNullOrWhiteSpace(this.importModulesCode[moduleName])))
        {
            string rawScript = this.importModulesCode[moduleName];
            this.engine.Execute(rawScript, this.scope);
            Scope ret = HostingHelpers.GetScope(this.scope);
            this.scope.SetVariable(moduleName, ret);
            return ret;
        }
        else
        {   // fall back on the built-in method
            return Builtin.__import__(context, moduleName);
        }
    }
}

现在这似乎工作正常。只是当我尝试运行Python代码时,我得到了堆栈溢出异常,因为引用似乎是递归的。

我的主要pyw文件包含以下标题:

import os, sys, getopt, __builtin__
from pyglossary.glossary import confPath, VERSION

第一次导入是os模块,我从IronPython Lib中取出,因此我的ImportModuleFromResources方法使用第一个if块并且引用得到解析。

下一次迭代尝试导入sys(使用else块和内置模块导入),然后errno(再次else块和内置-in module import) - &gt; nt(再次内置导入) - &gt; nt(再次......) - &gt; ntpath(是的..) - &gt;然后再次返回os,继续无限递归再次通过模块......(当然会导致堆栈溢出)。

由于我不是Python专家,而且我不了解IronPython的标准库模块以及它们如何相互引用,我确信我做的是一些非常基本的错误,但不确定我需要哪些参考取出,操纵我包含的一个Lib文件(不太可能,我认为),或改进我的ImportModuleFromResources方法以避免递归引用..

非常感谢帮助。谢谢!

1 个答案:

答案 0 :(得分:0)

我的做法与Einar Egilsson =&gt;中Custom IronPython import resolution已消化的方式相同使用PlatformAdaptationLayer

通过这种方式,ironpython使用自己的机制来搜索模块,并且只在找不到模块时才使用你的代码。