Есть ли способ вызвать код Python, используя, предположительно, IronPython, из С#? Если да, то как?
Как я могу вызвать (Iron) код Python из приложения С#?
Ответ 1
Процесс прост, особенно в приложении С#/.NET 4, где поддержка динамических языков улучшена с использованием типа dynamic
. Но все это в конечном итоге зависит от того, как вы собираетесь использовать (Iron) код Python в своем приложении. Вы всегда можете запустить ipy.exe
как отдельный процесс и передать исходные файлы, чтобы они могли быть выполнены. Но вы, вероятно, захотели разместить их в своем приложении С#. Это оставляет вам много вариантов.
-
Добавьте ссылку на сборки
IronPython.dll
иMicrosoft.Scripting.dll
. Обычно вы найдете их в корневом каталоге установки IronPython. -
Добавьте
using IronPython.Hosting;
в начало вашего источника и создайте экземпляр механизма сценариев IronPython с помощьюPython.CreateEngine()
. -
У вас есть пара вариантов, но в основном вы создадите
ScriptScope
илиScriptSource
и сохраните его как переменнуюdynamic
. Это позволяет выполнить его или управлять областями из С#, если вы решите это сделать.
Вариант 1:
Использование CreateScope()
для создания пустого ScriptScope
для непосредственного использования кода С#, но используемого в источниках Python. Вы можете рассматривать их как свои глобальные переменные в экземпляре интерпретатора.
dynamic scope = engine.CreateScope();
scope.Add = new Func<int, int, int>((x, y) => x + y);
Console.WriteLine(scope.Add(2, 3)); // prints 5
Вариант 2:
Использование Execute()
для выполнения любого кода IronPython в строке. Вы можете использовать перегрузку, в которой вы можете пройти в ScriptScope
для хранения или использования переменных, определенных в коде.
var theScript = @"def PrintMessage():
print 'This is a message!'
PrintMessage()
";
// execute the script
engine.Execute(theScript);
// execute and store variables in scope
engine.Execute(@"print Add(2, 3)", scope);
// uses the `Add()` function as defined earlier in the scope
Вариант 3:
Использование ExecuteFile()
для выполнения исходного файла IronPython. Вы можете использовать перегрузку, в которой вы можете пройти в ScriptScope
для хранения или использования переменных, определенных в коде.
// execute the script
engine.ExecuteFile(@"C:\path\to\script.py");
// execute and store variables in scope
engine.ExecuteFile(@"C:\path\to\script.py", scope);
// variables and functions defined in the scrip are added to the scope
scope.SomeFunction();
Вариант 4:
Используя метод расширения GetBuiltinModule()
или ImportModule()
, чтобы создать область, содержащую переменные, определенные в указанном модуле. Импортируемые таким образом модули должны быть установлены в пути поиска.
dynamic builtin = engine.GetBuiltinModule();
// you can store variables if you want
dynamic list = builtin.list;
dynamic itertools = engine.ImportModule("itertools");
var numbers = new[] { 1, 1, 2, 3, 6, 2, 2 };
Console.WriteLine(builtin.str(list(itertools.chain(numbers, "foobar"))));
// prints `[1, 1, 2, 3, 6, 2, 2, 'f', 'o', 'o', 'b', 'a', 'r']`
// to add to the search paths
var searchPaths = engine.GetSearchPaths();
searchPaths.Add(@"C:\path\to\modules");
engine.SetSearchPaths(searchPaths);
// import the module
dynamic myModule = engine.ImportModule("mymodule");
В ваших проектах .NET вы можете сделать довольно много кода Python. С# помогает преодолеть этот пробел, с которым легче справиться. Объединив все варианты, упомянутые здесь, вы можете сделать практически все, что захотите. Конечно, вы можете сделать больше с классами, найденными в пространстве имен IronPython.Hosting
, но этого должно быть более чем достаточно, чтобы вы начали.
Ответ 2
Чтобы запустить функцию, вы не можете называть ее, как в Варианте 3 ответа Джеффа Меркадо (что очень полезно и полезно! Но этот параметр не компилируется, по крайней мере, на.NET 4.5). Вы можете использовать ScriptScope.GetVariable для получения фактической функции, а затем вы можете назвать ее как функцию С#. Используйте его так:
Код С#:
var var1,var2=...
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
engine.ExecuteFile(@"C:\test.py", scope);
dynamic testFunction = scope.GetVariable("test_func");
var result = testFunction(var1,var2);
Код Python:
def test_func(var1,var2):
...do something...
Понадобился немного времени, чтобы наконец разобраться, и это довольно просто. Жаль, что нет хорошей документации IronPython. Надеюсь это поможет :)