This article will guide you through running a compiled Python script
(.pyc file) from a C# application, leveraging the capabilities of both languages.
Introduction
The interoperability between different programming languages enables developers to leverage the best features of each language. One such powerful combination is using Python and C# together.
I’m not a C# expert. This blogpost is purely based on my learning while I was trying to run a Python script from a C# application.
Prerequisites
- Python Installation: Ensure Python is installed on your machine and that
the Python executable is accessible via the system’s
PATH. You can download Python from the official Python website. - C# Development Environment: You’ll need an environment for writing and running C# code. Visual Studio is a popular choice, but you can use any editor or IDE of your choice.
A Python Script
In order to keep it simple, we will be using the following Python script:
def Greet(name):
return f"Hello, {name}!"
Save the file as greeter.py to follow along.
Before running a Python script from C#, you would typically compile it into a
.pyc file. Here’s how you can compile your Python script:
- Open a terminal or command prompt.
- Run the following command:
python3 -m compileall greeter.py
This command will generate a directory named __pycache__ containing the
compiled .pyc file. In our case:
➜ tree .
.
├── __pycache__
│ └── greeter.cpython-312.pyc
└── greeter.py
C# Application
We start off by creating a console application using the dotnet CLI:
mkdir netpy && cd netpy
dotnet new console
Next, we add the pythonnet package to the project:
dotnet add package pythonnet
Update the Program.cs file with the code below to run the compiled (.pyc)
Python script (greeter.py):
using Python.Runtime;
// Specify the path to the Python shared library (DLL or .so file)
Runtime.PythonDLL = "/opt/homebrew/Cellar/[email protected]/3.12.4/Frameworks/Python.framework/Versions/3.12/lib/libpython3.12.dylib";
// Initialize the Python engine
PythonEngine.Initialize();
// Use a try-finally block to ensure proper cleanup
try
{
// Acquire the GIL (Global Interpreter Lock)
using (Py.GIL())
{
// Add path to __pycache__ directory
dynamic sys = Py.Import("sys");
sys.path.append("/Users/gaurav.gahlot/workspace/playground/netpy");
// Import the compiled .pyc file
dynamic greeter = Py.Import("greeter");
// Call the Greet function
string result = greeter.Greet("Alice");
Console.WriteLine(result);
}
}
finally
{
// Necessary for proper serialization
AppContext.SetSwitch("System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", true);
// Shutdown the Python runtime
PythonEngine.Shutdown();
}
Detailed Explanation
Python.RuntimeInitialization:- You must set
Runtime.PythonDLLproperty orPYTHONNET_PYDLLenvironment variable starting with version 3.0, otherwise you will receiveBadPythonDllExceptionupon callingInitialize. - You can read more about the same in their documentation.
- You must set
- Initialize Python Engine:
PythonEngine.Initialize(): This initializes the Python engine, making Python functionalities available within the C# environment.
- Using Python with GIL:
using (Py.GIL()): Ensures that the Global Interpreter Lock (GIL) is acquired, which is necessary for thread-safety when interacting with Python objects.
- Modifying Python Path:
dynamic sys = Py.Import("sys")andsys.path.append("path"): Adds the__pycache__directory to the Python path. This is where the compiled.pycfile resides.
- Import and Execute:
dynamic greeter = Py.Import("greeter"): Imports the compiled Python script.string result = greeter.Greet("Alice"): Calls the Greet function from the imported script and prints the result.
- Clean Up:
AppContext.SetSwitch("System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", true): Ensures proper serialization. You can learn more about it in this GitHub issue.PythonEngine.Shutdown(): Properly shuts down the Python engine to clean up resources.
Running the Application
- Ensure that you have saved the code changes in
Program.cs. - Open your terminal and navigate to the directory containing
Program.cs - Run the application using
dotnet run:
workspace/playground/netpy via .NET 8.0.401
➜ dotnet run
Hello, Alice!
This will execute the Python script and print the output to the console.
Conclusion
Using Python.NET simplifies the process of integrating Python with C#. You can leverage the capabilities of Python directly from your C# applications, making it possible to use Python’s extensive libraries and simplicity alongside C#’s strong performance and robust framework.
I hope this helps you get started with running compiled Python scripts from C# applications smoothly.