Calling Python from C#: an introduction to PythonNET
Recently, I had to dig into PythonNET since I had to find a way to call Python scripts from my C# projects at work. Surprisingly enough, I found very little material online on the subject and most of it was contradictory or rather confusing. PythonNET’s official documentation wasn’t particularly helpful either, so I decided to write this guide for those who will find themselves in the same situation as me in the future.
Compile PythonNET’s dll
First thing we’re going to do is compiling PythonNET’s dll. Download PythonNET’s source code from Github, open it with Visual Studio and compile the project called “Python.Runtime”. If the compilation is successful, it will generate a .dll file in pythonnet-master\pythonnet\runtime\Python.Runtime.dll
Python prerequisites
At the moment when this guide was written (September 2021), PythonNET supports only Python 3.6–3.8. Python’s last available release is the 3.9.7. Check if you have a newer version of Python installed on your machine and, if that’s the case, be absolutely sure to uninstall it to avoid any problems. You can then download Python 3.8 from here.
If you have a version like “3.8.10” or something like that it should be fine, PythonNET doesn’t seem to mind until you reach 3.9 and up from my personal experience.
You will also need to install PythonNET’s module by launching pip install pythonnet from the CMD.
Create a test application
Let’s create a console application called “TestProject” and add a reference to PythonNET’s dll (Python.Runtime.dll) in it.
Hello world
Let’s create a class named “PythonInterop”. We are going to create an Initialize method, where we’re going to set Python’s dll as an environment variable (be sure to replace my path with yours) and Initialize PythonNET’s engine. You can find Python’s dll in Python’s installation path. By default, it should be C:\Users\YourUserNameHere\AppData\Local\Programs\Python\Python38\python38.dll. for Python 3.8.0.
NOTE: If you’re planning on running PythonNET on Linux, you want to look for Python’s .so file instead! It can be quite hard to find since it isn’t always found in the same directory. You can try to run this script to get its location:
wget https://gist.githubusercontent.com/tkf/d980eee120611604c0b9b5fef5b8dae6/raw/9f074cd233f83180676b4421212ed33c257968af/find_libpython.py
/usr/bin/python3 find_libpython.py --list-all
We are also going to create a method to run our Python code with PythonNET.
Now let’s go in Program.cs and launch our hello world.
Use C# classes in Python
To import C# classes, variables and methods into Python we need to import a module called clr.
Let’s create a class named “MyClass” with a string property named “MyVar”.
In our Program.cs file, let’s run
If everything went well, we should see our variable printed in the Console.
In this way we can import any class, including C#’s System classes, and use their methods too.
Use C# types from Python
In the same way, PythonNET lets us se C#’s types from Python aswell.
Import variables with PythonNET’s methods
An alternative way to import C# variables into Python is using PythonNET’s methods.
Let’s create an overload of the RunPythonCode method in our PythonInterop class
parameter is the variable that we want to inject into Python, parameterName is the name that we want the variable to have inside of Python (usually, the same as C#).
Let’s create a Person class and test our method.
Return values from Python to C#
Let’s suppose now that we want to return a variable from Python into C# to perform some other operations on it.
To do so, let’s go back into our PythonInterop class and create a method.
returnedVariableName is the name of the Python variable that we want to get returned in C#.
Let’s try to edit the Age property’s value, to assign it to a variable and to return it to C#.
Import from external projects
You can also easily import from external libraries using the clr module. Let’s create a class library called “MyLibrary” in our solution and let’s reference it from our main Console Application method.
After that, let’s add a class called “LibClass” in our library.
Now, let’s just try to print our string from Python.
Final notes
This was meant as a short introduction to PythonNET for absolute beginners, since it was so difficult for me to find material like this online.
From now on you will probably have a decent toolset that you can use to research and pursue your goals with PythonNET on your own. Good luck!
I’m going to leave the full source of the PythonInterop class below.