从模块

时间:2015-07-06 11:47:14

标签: c# python ironpython

我们在开源项目中使用IronPython。我有问题访问添加到脚本范围的变量,如

private ScriptScope CreateScope(IDictionary<string, object> globals)
{
    globals.Add("starting", true);
    globals.Add("stopping", false);

    var scope = Engine.CreateScope(globals);
    scope.ImportModule("math");
    return scope;
}

https://github.com/AndersMalmgren/FreePIE/blob/master/FreePIE.Core/ScriptEngine/Python/PythonScriptEngine.cs#L267

我可以使用主脚本中的全局变量,但任何加载的模块都将失败。如何解决?

更新:给定此模块 mymodule.py

if starting: #starting is defined on the scope
   ...

从使用此代码执行的主脚本

void RunLoop(string script, ScriptScope scope)
{
    ExecuteSafe(() =>
    {
        var compiled = Engine.CreateScriptSourceFromString(script).Compile();

        while (!stopRequested)
        {
            usedPlugins.ForEach(p => p.DoBeforeNextExecute());
            CatchThreadAbortedException(() => compiled.Execute(scope));
            scope.SetVariable("starting", false);
            threadTimingFactory.Get().Wait();
        }
        scope.SetVariable("stopping", true);
        CatchThreadAbortedException(() => compiled.Execute(scope));
    });
}

https://github.com/AndersMalmgren/FreePIE/blob/master/FreePIE.Core/ScriptEngine/Python/PythonScriptEngine.cs#L163

from mymodule import * #this will load the moduel and it fails with

enter image description here

编辑:回应@ BendEg的回答

我试过这个

scope.SetVariable("__import__", new Func<CodeContext, string, PythonDictionary, PythonDictionary, PythonTuple, object>(ResolveImport));

ImportDelegate未定义,因此尝试使用Func,ResolveImport方法永远不会触发,我得到的名称未定义相同的异常

编辑:我将范围创建更改为

var scope = Engine.GetBuiltinModule();
globals.ForEach(g => scope.SetVariable(g.Key, g.Value));

现在导入委托触发但是它在global name 'mouse' is not defined的第一行崩溃,模块中没有使用鼠标。当我将自定义全局变量添加到BuiltinModule

时,似乎很困惑

2 个答案:

答案 0 :(得分:1)

据我所知,导入一些模块会创建一个新范围。因此,当通过PythonModule创建from ... import ...的实例时,它们拥有自己的范围。在此新范围中,您的公共变量不可用。如果我错了,请纠正我。

解决方法:

您可以创建一些静态类,用于保存值。你可以肯定,你总是拥有它们。例如:

namespace someNS
{
    public static class SomeClass
    {
        public static bool Start { get; set; }
    }
}

而不是你的IP代码:

from someNS import SomeClass

# Now you can access the member
yourVal = SomeClass.Start

也许这是你可以使用的一些东西。您的事件不需要在范围内将其设置为变量。

修改

也许这对你有用。在代码中我覆盖模块导入并尝试设置全局变量:

首先需要的是,为IronPython提供一些委托,用于模块导入:

# Scope should be your default scope
scope.SetVariable("__import__", new ImportDelegate(ResolveImport));

然后覆盖导入功能:

private object ResolveImport(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple fromlist)
{
    // Do default import but set module
    var builtin = IronPython.Modules.Builtin.__import__(context, moduleName, globals, locals, fromlist, 0);
    context.ModuleContext.Module.__setattr__(context, "some_global", "Hello World");
    return builtin;
}

修改

ImportDelegate

的定义
delegate object ImportDelegate(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple fromlist);

答案 1 :(得分:0)

这可能不是正确的答案,因为仍然不允许与导入的模块共享IronPhyton主脚本中定义的变量,但这是向前的一步。

这种方法允许在引擎级别而不是脚本级别设置变量,并且它们将在每个导入的模块中可用。

engine = Python.CreateEngine();
engine.Runtime.Globals.SetVariable("test_global", "This is a test global variable.");

然后,可以在任何IronPhyton脚本中使用导入来访问它:

import test_global
print(test_global)

与ScriptScope使其直接可用不同,这些全局变量需要导入。

原创文章
https://ludovic.chabant.com/devblog/2009/12/24/exposing-global-variables-in-ironpython/

免责声明
我添加了这个答案,是因为我一直在努力寻找除该SO Q&A之外的其他任何有关该主题的材料,因此,我正在发布此可能的解决方法,以帮助将来遇到麻烦的读者(例如我自己)