IronPython integration in C #: specific problem / question

I am working on providing an extension mechanism for my application for creating maps in C # through IronPython. Everything works fine, but I have a special requirement that arises during implementation: I want the user to be able to specify two things:

  • Python script download file name
  • A single-layer string containing a Python script, which is usually a function call from this Python file (example getTextLabel(element) )

These two settings should be separate, but I don't know if this can be done using PythonScript and related classes.

I'm new to Python, maybe there is another way to achieve this? For performance reasons, I want to avoid loading and compiling the Python script file several times (since there may be several of the above different β€œfunction calls”, and I want to reuse the CompiledCode instance for the file, if possible).

UPDATE: @digEmAll gave the correct answer to my question, so I accept it as a valid answer. But if you are interested in performance, you should also check out my own answer.

+4
source share
2 answers

You can do something like this:

 string importScript = "import sys" + Environment.NewLine + "sys.path.append( r\"{0}\" )" + Environment.NewLine + "from {1} import *"; // python script to load string fullPath = @"c:\path\mymodule.py"; var engine = Python.CreateEngine(); ScriptScope scope = engine.CreateScope(); // import the module string scriptStr = string.Format(importScript, Path.GetDirectoryName(fullPath), Path.GetFileNameWithoutExtension(fullPath)); var importSrc = engine.CreateScriptSourceFromString(scriptStr,Microsoft.Scripting.SourceCodeKind.File); importSrc.Execute(scope); // now you ca execute one-line expressions on the scope eg string expr = "functionOfMyModule()"; var result = engine.Execute(expr, scope); 

As long as you save the scope where the module is loaded, you can call the module functions without reloading it.

+5
source

I did some testing of @digEmAll code. First I have to say that it works correctly and does what I asked in the question. But I was worried that you should call

 string expr = "functionOfMyModule()"; var result = engine.Execute(expr, scope); 

every time you want to evaluate a custom expression. My concern was that the code was not precompiled and had to be re-processed at each run, which could seriously affect the performance of my application (such expressions could be called hundreds of thousands, if not millions of times, so every millisecond is counted).

I tried another solution: just pasting a custom expression at the end of the Python module (I'm not saying this works in all situations!):

 def simpleFunc(x): return x + 2; # this is where the pasting occurs: simpleFunc(x) 

Then I had to compile this code:

  ScriptSource source = engine.CreateScriptSourceFromString(myCode); CompiledCode compiledCode = source.Compile(); 

... create a scope and run it:

  ScriptScope scope = engine.CreateScope(); scope.SetVariable ("x", 10); int result = compiledCode.Execute<int>(scope); 

Now I have executed both solutions (digEmAll and my own) on the same code fragment and the same expression 10,000 times, and here are the results:

  • engine.Execute (expr, scope): 0.29 ms / run
  • compiledCode.Execute (scope): 0.01 ms / run

So, I think that I will try to use my own solution if the code insert is not inserted.

+4
source

All Articles