Why can't I change variables from cached modules in IronPython?

家住魔仙堡 提交于 2020-01-05 03:45:02

问题


Disclaimer: I am new to python and IronPython so sorry if this is obvious.

We have a C# application that uses IronPython to execute scripts. There are a few common modules/scripts and then a lot of little scripts that define parameters, do setup, then call functions in the core modules. After some recent additions made the common modules larger performance took a hit on the imports. I attempted to fix this by making sure we only created one engine and created scopes for each script to run in. I've seen information that these are compiled on the engine, but this is apparently not so as it continued to take excessive time importing them so it must be cached in the scope. Then I used THIS blog entry to create a custom shared dictionary where I could precompile the common modules at app load and then reuse it. Everything was working fine until I realized that variables were not changing on subsequent runs. After creating a scope in which to run a script I would add a required variable...

currentScope.SetVariable("agr", aggregator)

The first time this runs agr works fine in the scripts and is say instance A. On subsequent runs a new scope is created, a new aggregator is created (let's call it B) and set as agr, but when the underlying modules call agr it is not aggregator B, its aggregator A which i no longer valid. I have even tried to force it adding this to the main script...

CommonModule.agr = agr

#Do Work

CommonModule.agr = None

to no avail. agr itself is not stored in the shared symbol dictionary, but CommonModule is and it has a variable for agr. What do I have to do to change this variable and why is it cached in this manner?

UPDATE FOR CLARIFICATION: Sorry about the confusion, but it's a combination of so much code across C# and python it would be hard to include. Let me see if I can clarify a little. Every time I run a script I need to set the value for 'agr' to a new object which is created in C# prior to python execution using scope.SetVariable(). Some core modules are imported and compiled into a cached scope. On script execution a new temporary scope is created using a SharedSymbolDictionary created with the shared scope (to avoid importing core modules every time) which executes the script.

The problem is 'agr' is set correctly the first time both in the main script and the core (precompiled) scripts, however on subsequent script executions 'agr' is correct in the main script, but when the core scripts reference 'agr' it is pointing to the 'agr' created the first execution and NOT the new 'agr' object created for that execution and most of its references are null now.


回答1:


All the comments without the code are a bit confusing. But taking just the last paragraph, if you would like to modify the module level variable from C# you can:

# scope is SharedSymbolDictionary
var module = scope.GetVariable("CommonModule") as PythonModule;
module.Get__dict__()["agr"] = "new value";

The second observation, the variables which are provided to SharedSymbolDictionary as sharedScope can be changed within the individual run, but disappear on subsequent runs. If you would like to make persistent changes during the script run, you need to change TrySetExtraValue to something like this:

    protected override bool TrySetExtraValue(string key, object value) {
        lock (_sharedScope) {
            if (_sharedScope.ContainsVariable(key)) {
                _sharedScope.SetVariable(key, value);
                return true;
            }
            return false;
        }
    }

Note: I work with Ironpython 2.7 and .Net 4.0. The signature of TrySetExtraValue is a bit different than the one in the blog.




回答2:


So I don't have a solid explanation, but I found a simple solution. Originally 'agr' was the variable name used everywhere... scope.SetVariable(), in the top level scripts, and in the precompiled core scripts.

For the fix, I changed the C# to use the variable name 'aggregator' for SetVariable(). I then created a module imported by all the top level main scripts i.e. sharedModule and then used...

sharedModule.agr = aggregator

Then I changed all core scripts to use sharedModule.agr instead of just 'agr' and that seems to work the way I want it.



来源:https://stackoverflow.com/questions/21046068/why-cant-i-change-variables-from-cached-modules-in-ironpython

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!