Python is a powerful and versatile programming language that has become increasingly popular. For many, it’s one of the very first programming languages they pick up when getting started. Some of the highest traffic posts on my blog many years after they were written look at using C# and Python together. Today we’re going to explore how you can use Python from inside a C# .NET Core application with much more modern approaches.
Enter Pythonnet!
We’re going to be looking at Python for .NET in order to accomplish this goal. This library allows you how to take advantage of Python installed on the running machine from within your .NET Core applications. You must configure it to point at the corresponding Python DLL that you’d like to use, and after a couple of lines of initialization, you’re off to the races!
To get started, you’ll need to install the pythonnet package from NuGet. Once you’ve done that, you can use the following code to run a Python script from your C# code:
using Python.Runtime;
internal sealed class Program
{
private static void Main(string[] args)
{
// NOTE: set this based on your python install. this will resolve from
// your PATH environment variable as well.
Runtime.PythonDLL = "python310.dll";
PythonEngine.Initialize();
using (Py.GIL())
{
using var scope = Py.CreateScope();
scope.Exec("print('Hello World from Python!')");
}
}
}
This code sets our python DLL path on the Runtime, which will be a necessary step. Don’t forget to do this! We must then call PythonEngine.Initialize() and Py.GIL(), which we will want to dispose of later so consider a using statement. We can ask the static Py class to create a scope for us to use, and then leverage the Exec method in order to execute some Python code. In this example, we’re calling the Exec method to run a simple Python script that prints “Hello World from Python!” to the console.
You can also use the Python C API to call Python functions directly from C# code. To do this, you’ll need to create a C# wrapper for the Python function you want to call. Here’s an example of how you might create a wrapper for a Python function that takes two integers as arguments and returns their sum:
using System;using Python.Runtime;
internal sealed class Program
{
private static void Main(string[] args)
{
// NOTE: set this based on your python install. this will resolve from
// your PATH environment variable as well.
Runtime.PythonDLL = "python310.dll";
PythonEngine.Initialize();
using (Py.GIL())
{
// NOTE: this doesn't validate input
Console.WriteLine("Enter first integer:");
var firstInt = int.Parse(Console.ReadLine());
Console.WriteLine("Enter second integer:");
var secondInt = int.Parse(Console.ReadLine());
using dynamic scope = Py.CreateScope();
scope.Exec("def add(a, b): return a + b");
var sum = scope.add(firstInt, secondInt);
Console.WriteLine($"Sum: {sum}");
}
}
}
In this example, we’re using the Exec method to define a Python function called “add” that takes two integers as arguments and returns their sum. Thanks to the dynamic keyword in C#, we are able to make an assumption that our scope object has a method called “add” directly on it. Finally, we use C# code directly to call the “add” method just like as if it was inside of C#. The return type assigned to the “sum” variable in C# is also dynamic, but you could declare this variable as an integer and it will compile properly with this type as well.
Also published here as a full article.