【问题标题】:Accesing script scope variables from modules从模块访问脚本范围变量
【发布时间】:2020-07-23 14:05:44
【问题描述】:

我们在开源项目中使用 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

编辑:回应@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

时,它似乎很困惑

【问题讨论】:

  • 您能否提供一个更完整的示例(例如,针对该范围执行了什么以及它如何失败)?

标签: c# python ironpython


【解决方案1】:

这可能不是正确的答案,因为仍然不允许将在 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 之外的有关此主题的任何材料,因此我发布此可能的解决方法以提供帮助未来陷入困境的读者(比如我自己)

【讨论】:

    【解决方案2】:

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

    解决方法:

    您可以创建一些静态类来保存值。可以肯定的是,您始终拥有它们。例如:

    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);
    

    【讨论】:

    • 有解决办法吗?因为我们确实需要让我们的全局静态变量可以从任何代码访问
    • 恐怕不是一个可靠的解决方案。我们有一个插件结构,每个插件都在作用域上注册一个名称,因此您可以像 mouse.deltaX 或 keyboard.getKey(Key.A) 一样访问它
    • 使用一些静态的DynamicObject怎么样?
    • @Anders 我有更好的解决方案,请等待 2 分钟 :)
    • 只是想深入挖掘 IronPython 的核心,我们公司使用 IronPython,所以目前与它有很大关系:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-16
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多