How can I call (Iron)Python code from a C# app?
The process is simple, especially in a C#/.NET 4 application where support for dynamic languages have been improved via usage of the dynamic
type. But it all ultimately depends on how you intend to use the (Iron)Python code within your application. You could always run ipy.exe
as a separate process and pass your source files in so they may be executed. But you probably wanted to host them in your C# application. That leaves you with many options.
Add a reference to the
IronPython.dll
andMicrosoft.Scripting.dll
assemblies. You'll usually find them both in your root IronPython installation directory.Add
using IronPython.Hosting;
to the top of your source and create an instance of the IronPython scripting engine usingPython.CreateEngine()
.You have a couple of options from here but basically you'd create a
ScriptScope
orScriptSource
and store it as adynamic
variable. This allows you to execute it or manipulate the scopes from C# if you choose to do so.
Option 1:
Using CreateScope()
to create an empty ScriptScope
to use directly in C# code but usable in Python sources. You can think of these as your global variables within an instance of the interpreter.
dynamic scope = engine.CreateScope();
scope.Add = new Func<int, int, int>((x, y) => x + y);
Console.WriteLine(scope.Add(2, 3)); // prints 5
Option 2:
Using Execute()
to execute any IronPython code in a string. You can use the overload where you may pass in a ScriptScope
to store or use variables defined in the code.
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
Option 3:
Using ExecuteFile()
to execute an IronPython source file. You can use the overload where you may pass in a ScriptScope
to store or use variables defined in the code.
// 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();
Option 4:
Using GetBuiltinModule()
or the ImportModule()
extension method to create a scope containing the variables defined in said module. Modules imported this way must be set in the search paths.
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");
You can do quite a lot hosting Python code in your .NET projects. C# helps bridging that gap easier to deal with. Combining all the options mentioned here, you can do just about anything you want. There's of course more you can do with the classes found in the IronPython.Hosting
namespace, but this should be more than enough to get you started.
How do I call Python scripts with packages from IronPython?
I found the error. Search paths for the needed modules must be included. Here is an example.
var engine = Python.CreateEngine();
var searchPaths = new List<string>();
searchPaths.Add(AppDomain.CurrentDomain.BaseDirectory + @"\Lib\site-packages");
searchPaths.Add(@"C:\...\projectName\Lib\");
engine.SetSearchPaths(searchPaths);
engine.ExecuteFile("test.py");
Run a particular Python function in C# with IronPython
Thanks to suggestion in comments I was able to figure out how to use it. Here's what I have now:
public class PythonInstance
{
private ScriptEngine engine;
private ScriptScope scope;
private ScriptSource source;
private CompiledCode compiled;
private object pythonClass;
public PythonInstance(string code, string className = "PyClass")
{
//creating engine and stuff
engine = Python.CreateEngine();
scope = engine.CreateScope();
//loading and compiling code
source = engine.CreateScriptSourceFromString(code, Microsoft.Scripting.SourceCodeKind.Statements);
compiled = source.Compile();
//now executing this code (the code should contain a class)
compiled.Execute(scope);
//now creating an object that could be used to access the stuff inside a python script
pythonClass = engine.Operations.Invoke(scope.GetVariable(className));
}
public void SetVariable(string variable, dynamic value)
{
scope.SetVariable(variable, value);
}
public dynamic GetVariable(string variable)
{
return scope.GetVariable(variable);
}
public void CallMethod(string method, params dynamic[] arguments)
{
engine.Operations.InvokeMember(pythonClass, method, arguments);
}
public dynamic CallFunction(string method, params dynamic[] arguments)
{
return engine.Operations.InvokeMember(pythonClass, method, arguments);
}
}
To test it:
PythonInstance py = new PythonInstance(@"
class PyClass:
def __init__(self):
pass
def somemethod(self):
print 'in some method'
def isodd(self, n):
return 1 == n % 2
");
py.CallMethod("somemethod");
Console.WriteLine(py.CallFunction("isodd", 6));
Running C# Executable From Iron Python
It's worth noting that IronPython and Python are not the same thing. IronPython is built on the .NET framework and so should subscribe to all the usual features of .NET (like cross-compatibility, similar to C# and VB.NET code being able to interact).
I believe that this is the general concept you're looking for:
Instantiating custom C# classes from IronPython
i.e. Something like the following:
import clr
clr.AddReference('MyAssemblyWhichContainsForm.dll')
import MyForm
obj = MyForm("form title")
obj.Show()
Call Python function from c# (.NET)
You can call everything through your command line
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "python whatever";
process.StartInfo = startInfo;
process.Start();
Or even better, just call Python.exe
and pass your py
files as its argument:
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "Python.exe";
startInfo.Arguments = "yourfile.py";
process.StartInfo = startInfo;
process.Start();
Related Topics
How to Stream Webcam Video with C#
Is There a C# Case Insensitive Equals Operator
Log4Net Rolling Daily Filename with Date in the File Name
How to Get a JSON String from Url
Copy Constructor Versus Clone()
What Are the Definitions for Lparam and Wparam
Passing a Vector/Array from Unmanaged C++ to C#
How to Marshal a Struct That Contains a Variable-Sized Array to C#
Pass C# String to C++ and Pass C++ Result (String, Char*.. Whatever) to C#
How to Intercept All Key Events, Including Ctrl+Alt+Del and Ctrl+Tab
How to Find All Possible Subsets of a Given Array
How to Convert an Object to a Byte Array in C#
How to Get a JSON String from Url
How to Return Text from Native (C++) Code
How to Add CSS Class to HTML Generic Control Div