IronPython integration in C#: a specific problem/question

本小妞迷上赌 提交于 2020-01-10 03:08:45

问题


I'm working on providing an extensibility mechanism for my C# mapmaking application through IronPython. Everything works fine, but I have a specific requirement which I'm having trouble implementing: I want the user to be able to specify two things:

  1. A file name of the Python script to be loaded
  2. A one-liner string containing Python script which would typically be a call of a function from that Python file (example getTextLabel(element))

These two settings must be separate, but I don't know if it is possible to do this using PythonScript and related classes.

I'm a newbie in Python, perhaps 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 could be several above mentioned different "function call" settings and I want to reuse the CompiledCode instance for the file if possible).

UPDATE: @digEmAll gave the correct answer to my question, so I'm accepting it as a valid answer. But if you are concerned with performance, you should also check out my own answer.


回答1:


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 e.g.
string expr = "functionOfMyModule()";
var result = engine.Execute(expr, scope);

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




回答2:


I've done some testing of @digEmAll's code. First I must say it runs correctly and does what I asked in the question. But I was concerned with the fact that you have to call

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

every time you want to evaluate a user-defined expression. My concern was that the code is not pre-compiled and has to be reparsed on each execution, which could have a serious effect on the performance of my application (these kinds of expressions could be called hundreds of thousands if not millions of times, so every millisecond counts).

I tried a different solution: simply pasting the user-defined 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)

What I did then is 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 executed both solutions (digEmAll's and my own) on the same piece of code 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 guess I'll try to use my own solution, unless the code pasting proves to be a problem.



来源:https://stackoverflow.com/questions/5292366/ironpython-integration-in-c-a-specific-problem-question

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