【超簡単】C#からPython関数を直接コール!pythonnet(Python.Runtime)の実力を検証。

当ページのリンクには広告が含まれています。

UIに強みを持つC#に対し、データ処理や機械学習の分野ではPythonが圧倒的な優位性を誇ります。
C#からPythonを利用する手段として一般的な「プロセスコール」は、プロセスの起動によるオーバーヘッドやファイル経由のデータ連携の煩雑さが課題となることも。そこで注目したいのが、C#からPythonの豊富なライブラリへ直接アクセスできる「pythonnet(Python.Runtime)」です。

本記事では、C#からPythonの関数を直接呼び出す方法を、具体的なコード例を交えてわかりやすく解説します。
List、Dictionary、DataTableなどのC#データ型をPythonに渡す方法や、Python側からDataFrameやNumPy配列を受け取る方法に加え、関数呼び出し時のオーバーヘッドについても詳しく解説します。

さらに、C#からPythonを簡潔かつ安全に操作できるユーティリティクラス「PythonManager」や、DataFrame⇔DataTableの相互変換を可能にする拡張メソッド「DataTableExtensions」も紹介していますので、コピペで簡単にご利用いただけます。

pythonnetを使って、C#からPythonの強力な機能を取り入れたい方は、ぜひ最後までご一読ください。

本記事はC#からPython関数を呼び出す機能に限定しています。PythonからC#を呼び出す場合は、「【Python×C#】pythonnet でDLL連携!実務で使えるパフォーマンス最適とは?」の記事をご覧ください。

目次

Pythonnet(Python.Runtime)とは

Pythonnet(正式名称:Python for .NET) は、.NETアプリケーションからPythonコードを直接呼び出すためのライブラリです。
内部的には Python.Runtime.dll を通じて Python の実行環境(CPython)とやり取りし、C# から Python 関数・クラス・モジュールなどを操作できるようにします。

たとえば、以下のような用途で活躍します。

  • C# アプリから Python のデータ処理ロジックや機械学習モデルを実行
  • UI や業務アプリは C#、バックエンドの分析処理は Python で分離
  • Python のサードパーティライブラリ(NumPy, pandas, scikit-learn など)をそのまま C# から活用

Pythonnet の公式ドキュメント:https://pythonnet.github.io/pythonnet/

特徴

  • 双方向連携が可能
    Python から C# のオブジェクトを操作することもできる(ただし C# → Python の方が主流)
  • 同一プロセス内で実行されるため高速
    プロセス間通信を使う方法(例:標準出力/標準入力、REST API)と比べて、起動オーバーヘッドが小さい
  • ほぼすべてのPythonライブラリが利用可能
    通常のPythonスクリプトと同様に、pipでインストールした外部ライブラリも使用可能

仕組み

Pythonnet は、CPython(公式のPython実装)を内部で起動し、そのインタープリタに命令を送ることで動作します。
具体的には、Python.Runtime 名前空間を通じて Py.GIL(), Py.Import(), PyObject.InvokeMethod() といったインターフェースを使い、Pythonのコードやオブジェクトを制御します。

Pythonnet は IronPython とは異なります。 IronPython は .NET 上で動作する Python 実装(Python 2系ベース)で、C拡張モジュールが使えません。
一方 Pythonnet は公式の CPython を使うため、NumPy や TensorFlow なども利用できます。

インストール方法

C#側

Python.Runtimeのインストールが必要です。Python.RuntimePythonnet の主要パッケージ名であり、下記のキーワードをNuGet で検索し、インストールすれば準備完了です。

pythonnet

尚、pythonnetは .NET Framework 4.6.1 以降.NET (Core) 2.x 以降 (これには .NET 6.NET 8 が含まれます)に対応しています。
但し、2025年7月時点において、pythonnet のバグにより .NET 7 以降の動作が一部不安定になることがあるため、安定性を望むのであれば、 .NET 6 を採用するのが無難です。

Python側

Python側は、CPython(C言語で書かれたPythonのこと)であれば何でも構いません。Python公式サイト、Anaconda、Miniconda、WinPythonなどでPythonプログラムが実行できる環境を用意します。
2025年7月現在において、C#から呼び出し可能なpython バージョンは 3.7~3.13 です。

環境名特徴とおすすめポイント
Anaconda科学計算ライブラリが多数同梱。データ分析向け。仮想環境管理も GUI で簡単
Miniconda軽量版 Anaconda。必要なパッケージだけを conda install で追加できる
WinPythonポータブル構成で環境汚染せず、PythonHome 指定しやすい。実験に最適。
公式 Pythonpython.org 配布の標準環境。自由度が高く、最も素直に動く

どれを選べば良いか迷った方は、「Pythonインストールはどれを選べばいい?」の記事でそれぞれの特徴を詳しく記載していますので、ご一読ください。

pythonnet の使い方

C#側では、必ず下記の参照宣言を記述しておく必要がありますが、Python側の import は不要です。

using Python.Runtime;

C#側の記述

C# から Python の関数を呼び出すには、Python DLL のパス、Python のホームディレクトリ(EXEのルート)、Python の環境パス(Lib や site-packages など)を指定して、PythonEngine.Initialize() により Python ランタイムを初期化する必要があります。
使用後は、PythonEngine.Shutdown() によって明示的にランタイムを終了させることが推奨されます。

ここで重要なのが Py.GIL() の扱いです。

Python は内部に「GIL(Global Interpreter Lock)」という排他制御機構を持っており、Python オブジェクトにアクセスする処理は必ず GIL を取得した状態で行わなければなりません。
Pythonnet では using (Py.GIL()) { ... } のブロック構文を用いることで、C# から Python に安全にアクセスできるようになります。

  • モジュールのインポート(Py.Import()
  • Python の関数呼び出し(例: mod.greet("名前")
  • 属性の読み取り・書き換え(例: mod.version

これらの操作はすべて、GIL が必要です。GIL を持たずに Python オブジェクトを操作すると例外が発生する可能性があります。

Runtime.PythonDLL = "Python DLLのパス"; // 例:Python 3.12なら python312.dll
PythonEngine.PythonHome =
"Python.EXEのパス";
PythonEngine.PythonPath =
"Pythonの環境変数"; // Lib,site_packages,Pythonプログラムのパス

PythonEngine.Initialize(); // Python ランタイム初期化
using (Py.GIL()) // GIL(グローバルインタプリタロック)の取得
{
dynamic module = Py.Import("Pythonモジュール"); // 使いたい関数を含む
モジュールをインポート
module.関数名(引数,・・・); // 関数の呼び出し

  // ~~ 処理 ~~
}

PythonEngine.Shutdown(); // Python ランタイム終了

下記は、WinPythonが oドライブ直下の WPy64-39100 フォルダに格納されている事を想定したプログラム例です。
呼び出したい関数を含むPythonモジュール(hello.py)は、C#のEXEファイルが置かれているフォルダ配下の srcフォルダに置かれているものとします。

// Python インタープリタの場所
string home = @"O:\WPy64-39100\python-3.9.10.amd64";

// 実行したいPythonプログラムの場所
// 今回は、EXEと同じフォルダ配下のsrc フォルダに置く
string script_path = @".\src";

// Python Runtime DLLのパスを指定
Runtime.PythonDLL = $@"{home}\python39.dll";

// Python 実行環境のパスを設定
// (PythonPathの末尾に、実行したいPythonプログラムのパスを追加)
PythonEngine.PythonHome = home;
PythonEngine.PythonPath = $@"{home}\Lib;{home}\Lib\site-packages;{script_path};";
PythonEngine.Initialize(); // Python ランタイム初期化

using (Py.GIL()) // GIL(グローバルインタプリタロック)の取得
{
    dynamic hello = Py.Import("hello");
    string message = hello.greet("パイソン");
    Console.WriteLine(message); 
}

PythonEngine.Shutdown(); // Python ランタイム終了

Python側の記述

Python側は pythonnet を import する必要はありません。普通にプログラム(関数やクラス)を書くだけでOKです。

def greet(name):
    return f"こんにちは、{name}さん!"

C#からPythonを呼ぶときの注意点

PythonとC#でデータ型の表現が違うため、型変換や挙動に注意が必要です。

引数の渡し方

基本型(下記)の受け渡しについては、自動で型変換されるので、特別な処理は不要ですが、コレクションや構造体については明示的に型変換(ToPython()PyObjectに変換)することで挙動が安定します。
特に DateTime は互換性が低いため、事前に文字列にして渡すことが最も確実です。

C# 型Python 側の挙動備考・補足
string, int, double, bool自動で str, int, float, bool へ変換明示的な変換は不要。基本型は自然に渡せる
単純なListlist に変換可能ToPython() 推奨。明示的な変換で Python 側の型が安定
単純なDictionarydict に変換可能ToPython() で明示すると型ブレが防げる
ネストされたDictonaryネストされた dictPython 側で型チェック必須。C# 側で展開・変換を考慮した方が安全
DateTime文字列または未変換.ToString("o") で ISO 8601 に変換し、Python で再構成するのがベスト
// 単純な数値やデータ型なら、そのまま引数に渡すことが可能
int result = mymodule.myfunc(3, 7);

// リストの場合は、ToPython() で PyObject型に変換したものを引数として渡すと挙動が安定する
List<int> list = new List<int>{1,2,3};
PyObject pyList = list.ToPython();
mymodule.myfunc(pyList);

// 辞書の場合も、ToPython() で PyObject型に変換したものを引数として渡すと挙動が安定する
Dictionary<string, int> dic= new Dictionary<string, int>{{"apple",5},{"banana",3},{"orange",7}};
PyObject pyDict = dic.ToPython();  // 明示的な変換で安定性アップ
mymodule.myfunc(pyDict);

// 配列の場合も、ToPython() で PyObject型に変換したものを引数として渡すと挙動が安定する
int[] arr = { 10, 20, 30 };
PyObject pyList = arr.ToPython();
mymodule.myfunc(pyList);

戻り値の受け取り(str,int,float,list,dict など)

string や int などの単純なデータ型については、Pythonからそのまま受け取ることができます。

dynamic message = mod.greet("山田太郎"); // Python: return f"こんにちは、{name}さん"
Console.WriteLine((string)message);

list や dictのような、オブジェクトや配列をPythonから受け取る場合、PyObject型の変数で受けてから、Asメソッドで型変換を行います。

// Python関数 から list で戻り値を受け取るサンプル
PyObject raw = mod.get_data(); // Python 関数
var managedList = raw.As<List<string>>(); // List型に変換
foreach (var element in managedList ) 
{
    Console.WriteLine(element);
}

// Python関数から dict で戻り値を受け取るサンプル
PyObject raw = mod.get_data(); // Python 関数
var dict = raw.As<Dictionary<string, object>>(); // Dictionary型に変換
foreach (var kv in dict)
{
    Console.WriteLine($"{kv.Key} = {kv.Value}");
}

戻り値の受け取り(NumPy)

Numpy のデータ型はC#で直接受け取れないため、Python 側でリスト型に変換( tolist)した結果を返すのが最も簡単です。

# Python 側で np.array を list に変換して return する

import numpy as np

def get_array():
    a = np.array([1, 2, 3, 4])
    return a.tolist()  # Python の list に変換して返す
// C# では、受け取った戻り値を As<List<int>> を使ってリスト型に変換し使う

dynamic mod = Py.Import("utils");
PyObject pyList = mod.get_array();
var result = pyList.As<List<int>>();  // ← C# の List<int> で受け取れる}

戻り値の受け取り(DataFrame)

DataFrameも直接C#側では受け取れないため、辞書形式にして返します。この時、 to_dict(orient="records")で辞書のリスト(行ごとにカラムと値が辞書形式に変換されたもの)に変換したものを戻り値にすると、C#側で取り扱いが簡単になります。

# DataFrame は辞書のリストに変換したものを戻り値として返す

import pandas as pd

def get_df_dict():
    df = pd.DataFrame({
        "A": [1, 2],
        "B": [3, 4]
    })
    return df.to_dict(orient="records")  # [{'A': 1, 'B': 3}, {'A': 2, 'B': 4}]

C#側では、AsメソッドでList<Dictionary<string,object>>に変換すれば受け取れるはずなのですが、Listの中に辞書が含まれる場合は、うまくいかない場合があります

// Asメソッドで List<Dictionary<string, object>> に変換することで、表イメージで取り出せる。
// 但し、うまくいかない場合もある。

dynamic mod = Py.Import("utils");
PyObject data = mod.get_df_dict();
var rows = data.As<List<Dictionary<string, object>>>();

foreach (var row in rows)
{
    Console.WriteLine($"A: {row["A"]}, B: {row["B"]}");
}

そんな時は、PyList()に変換してから、ループ処理で辞書を1つづつ展開していけば全てのデータを取り出すことができます。

// List<Dictionary<string, object>> で変換できない場合は、PyList() でリストに変換すれば取り出せる。
using (Py.GIL())
{
    dynamic mod = Py.Import("utils");
    PyObject data = mod.get_df_dict();

    var pyList = new PyList(data); // list[dict] を PyList に変換

    foreach (PyObject pyItem in pyList)
    {
        var dict = new PyDict(pyItem); // 各 dict を PyDict に変換

        string a = dict[new PyString("A")].ToString();
        string b = dict[new PyString("B")].ToString();

        Console.WriteLine($"A: {a}, B: {b}");
    }
}

便利クラスと便利拡張メソッド

pythonnet でPython関数を呼び出す便利クラス

PythonEngineの初期化とPythonモジュールのインポート、PythonEngineのリソース解放が簡単に行えるクラスのサンプルを作成しました。

下記は、hello.py という名前のPythonファイルに、greetメソッドが記述されていることを前提とした、使い方のサンプルプログラムです。

using System;
using Python.Runtime;

using var py = new PythonManager(
   pythonHome: @"O:\WPy64-39100\python-3.9.10.amd64",
   pythonDllPath: @"{home}\python39.dll",
   pythonScriptPath: @".\src"
);

dynamic hello = py .ImportModule("hello");

// GIL 保護付きで Python 関数を呼び出す
string result = py.InvokeMethod(() => hello.greet("ぱいそん"));
Console.WriteLine(result);  // 出力: こんにちは、ぱいそんさん!

クラスのソースコードは以下の通りです。

using Python.Runtime;
using System;
using System.Collections.Generic;
using System.Data;

/// <summary>
/// Python 環境との連携を簡素化するユーティリティクラス。<br/>
/// DLLパスや環境パスの指定、PythonEngine の初期化・終了、モジュールのインポートを提供。
/// </summary>
public class PythonManager : IDisposable
{
    private bool initialized = false;

    /// <summary>
    /// PythonEngine を初期化し、Python 環境情報を設定します。
    /// </summary>
    /// <param name="pythonHome">Python のホームディレクトリ。</param>
    /// <param name="pythonDllPath">使用する pythonXY.dll のフルパス。{home} で phthonHome の値を指定可能</param>
    /// <param name="pythonScriptPath">Python モジュールを配置したソースパス。{home} で phthonHome の値を指定可能</param>
    /// <param name="libPath">Python 標準ライブラリのパス。{home} で phthonHome の値を指定可能</param>
    public PythonManager(string pythonHome, string pythonDllPath, string pythonScriptPath, string libPath = @"{home}\Lib;{home}\DLLs;{home}\Lib\site-packages;")
    {
        if (!initialized)
        {
            Runtime.PythonDLL = pythonDllPath.Replace("{home}", pythonHome);
            PythonEngine.PythonHome = pythonHome;
            PythonEngine.PythonPath = $"{libPath};{pythonScriptPath};".Replace("{home}",pythonHome);
            PythonEngine.Initialize();
            initialized = true;
        }
    }

    /// <summary>
    /// 指定した Python モジュールをインポートし、dynamic オブジェクトとして返します。
    /// </summary>
    /// <param name="moduleName">インポートする Python のモジュール名。</param>
    /// <returns>dynamic 型の Python モジュールオブジェクト。</returns>
    /// <exception cref="InvalidOperationException">PythonEngine が初期化されていない場合。</exception>
    public dynamic ImportModule(string moduleName)
    {
        if (!initialized) throw new InvalidOperationException("PythonEngine not initialized.");
        using (Py.GIL())
        {
            return Py.Import(moduleName);
        }
    }

    /// <summary>
    /// Python モジュールの関数を GIL 保護下で呼び出すユーティリティ。
    /// </summary>
    /// <typeparam name="T">戻り値の型</typeparam>
    /// <param name="pythonCall">呼び出したい Python 関数を含む delegate。</param>
    /// <returns>関数実行結果。</returns>
    public T InvokeMethod<T>(Func<T> pythonCall)
    {
        using (Py.GIL())
        {
            return pythonCall();
        }
    }

    /// <summary>
    /// PythonEngine をシャットダウンし、リソースを解放します。
    /// </summary>
    public void Shutdown()
    {
        if (initialized)
        {
            PythonEngine.Shutdown();
            initialized = false;
        }
    }

    /// <summary>
    /// IDisposable の実装。PythonEngine をシャットダウンします。
    /// </summary>
    public void Dispose() => Shutdown();
}

.NET 8.0以降で発生する「System.NotSupportedException」エラーの対処法

.NET 8.0以降では、Shutdown() を実行したタイミングで、下記のエラーが発生する場合があります。

.NET 8 ではセキュリティ向上のため、BinaryFormatter に関連する機能が完全に廃止されました。
これにより、PythonEngine.Shutdown() 実行時に内部で BinaryFormatter を使用している Pythonnet が System.NotSupportedException をスローするケースがあります。

今後 Pythonnet が正式に .NET 8 に対応した場合、この差し替えは不要になる可能性がありますが、それまでは、 Shutdown() メソッドの部分を下記のソースに置き換えてご利用ください。

	public void Shutdown()
	{
	    if (initialized)
	    {
	        // .NET 8 以降では BinaryFormatter が廃止されているため、
	        // Shutdown() 時の例外回避用に安全な Formatter を設定。
	        // Pythonnet が正式対応したら、下記1行をコメントアウトしてOK。
	        Python.Runtime.RuntimeData.FormatterType = typeof(NoopFormatter);

	        // PythonEngineのシャットダウン(リソース解放)を実施
	        PythonEngine.Shutdown();
	        initialized = false;
	    }
	}
	
	#pragma warning disable SYSLIB0011
	/// <summary>
	/// .NET 8 対応のためのダミー Formatter。
	/// 実際のシリアライズ処理は行わず、Shutdown 時の例外を防ぐ目的で使用。
	/// Pythonnet が正式対応したら、下記のクラスは削除してOK
	/// </summary>
	private class NoopFormatter : IFormatter
	{
	    public object Deserialize(Stream s) => throw new NotImplementedException();
	    public void Serialize(Stream s, object o) { }
	    public SerializationBinder Binder { get; set; }
	    public StreamingContext Context { get; set; }
	    public ISurrogateSelector SurrogateSelector { get; set; }
	}
	#pragma warning restore SYSLIB0011

DataFrame⇔DataTable 変換拡張メソッド

DataFrameと DataTable を相互変換するための便利な拡張メソッドも参考までに作成しました。
あらかじめ、下記のPythonプログラム(example.py)を準備しておきます。

# example.py

import pandas as pd

def load_table(records):
    df = pd.DataFrame(records)
    print(df)

def get_table():
    df = pd.DataFrame({
        "Fruit": ["Apple", "Banana", "Orange"],
        "Quantity": [5, 3, 8]
    })
    return df.to_dict(orient="records")  # ← C# で展開しやすい形式

下記が拡張メソッドのサンプルプログラムです。PythonManagerの引数は、ご自身の環境に合わせて適宜修正してください。

using System;
using System.Data;
using Python.Runtime;


using var py = new PythonManager(
   pythonHome: @"O:\WPy64-39100\python-3.9.10.amd64",
   pythonDllPath: @"{home}\python39.dll",
   pythonScriptPath: @".\src"
);

dynamic mod = py.ImportModule("example");

// C# → Python に DataTable を渡す
var table = new DataTable();
table.Columns.Add("Name");
table.Columns.Add("Age", typeof(int));
table.Rows.Add("武史", 42);
table.Rows.Add("美咲", 35);

PyObject pyTable = table.ToPythonDictRecords(); // 拡張メソッドで変換
mod.load_table(pyTable); // Python側で DataFrame に変換して表示

// Python → C# に dict(records) を戻して DataTable に展開
PyObject pyResult = py.InvokeMethod(() => mod.get_table());
DataTable resultTable = pyResult.ToDataTable(); // 拡張メソッドで復元

foreach (DataRow row in resultTable.Rows)
{
    Console.WriteLine($"{row["Fruit"]}: {row["Quantity"]}");
}

下記は拡張メソッドの全ソースです。

using Python.Runtime;
using System.Data;
using System.Collections.Generic;

/// <summary>
/// DataTable と Python 間のデータ変換を支援する拡張メソッド群。
/// Python に渡す際は dict(records) 形式に変換し、戻す際は PyObject を DataTable に復元する。
/// </summary>
public static class DataTableExtensions
{
    /// <summary>
    /// DataTable を Python 側で扱いやすい dict(records) 形式(list[dict])に変換し、PyObject にラップする。
    /// </summary>
    /// <param name="table">変換対象の C# DataTable。</param>
    /// <returns>Python 側で list[dict] として扱える PyObject。</returns>
    public static PyObject ToPythonDictRecords(this DataTable table)
    {
        var records = new List<Dictionary<string, object>>();

        foreach (DataRow row in table.Rows)
        {
            var dict = new Dictionary<string, object>();
            foreach (DataColumn col in table.Columns)
                dict[col.ColumnName] = row[col];

            records.Add(dict);
        }

        return records.ToPython(); // 拡張メソッド (Python.Runtime)
    }

    /// <summary>
    /// Python 側から返された dict(records) 形式(list[dict])を C# の DataTable に変換する。
    /// </summary>
    /// <param name="pyRecords">Python 側の list[dict] を含む PyObject。</param>
    /// <returns>復元された C# の DataTable。</returns>
    public static DataTable ToDataTable(this PyObject pyRecords)
    {
        var table = new DataTable();

        using (Py.GIL())
        {
            var pyList = new PyList(pyRecords); // ★ PyList に変換

            foreach (PyObject pyItem in pyList)
            {
                var dict = new PyDict(pyItem); // ★ PyDict に変換

                if (table.Columns.Count == 0)
                {
                    foreach (PyObject key in dict.Keys())
                    {
                        table.Columns.Add(key.ToString());
                    }
                }

                var row = table.NewRow();
                foreach (PyObject key in dict.Keys())
                {
                    var value = dict[key];
                    row[key.ToString()] = value.IsNone() ? DBNull.Value : value.AsManagedObject(typeof(object));
                }

                table.Rows.Add(row);
            }
        }

        return table;
    }
}

オーバーヘッドの検証

簡単なPython関数の呼び出しにおいて、「Pythonnetによる直接呼び出し」と「Shell(プロセス)起動」の2通りの方式で処理速度を比較しました。

結果として、Shell起動に比べてPythonnetのオーバーヘッドは約1/3〜1/4に収まり、2回目以降の呼び出しに至ってはオーバーヘッドがほぼゼロであることが確認されました。

一方、Shell起動は2回目以降の実行で若干高速化する傾向が見られたものの、関数呼び出しのたびに一定のオーバーヘッドが発生しており、連続処理に向かないことがわかります。

実行回数Pythonnetによる直接呼出しShell起動
1回目34 ms114 ms
2回目0 ms99 ms
3回目0 ms101 ms
4回目0 ms100 ms
5回目0 ms99 ms

検証に使ったPCのスペック:Core(TM) i5-13400 (2.50 GHz) 48.0 GB Windows11 Pro 24H2

C#からShell起動による連携方法については、「【コピペで完了】C#からPythonを呼び出して結果を表示!」の記事をご覧ください。

テストコード

Pythonプログラムのソースコード

def greet(name):
    return f"こんにちは、{name}さん!"

C#側のソースコード

private void pythonnet()
{
    // Python インタープリタの場所
    string home = @"O:\WPy64-39100\python-3.9.10.amd64";
    // 実行したいPythonプログラムの場所
    // 今回は、EXEと同じフォルダ配下のsrc フォルダに置く
    string script_path = @".\src";

    // Python Runtime DLLのパスを指定
    Runtime.PythonDLL = $@"{home}\python39.dll";

    // Python 実行環境のパスを設定
    // (PythonPathの末尾に、実行したいPythonプログラムのパスを追加)
    PythonEngine.PythonHome = home;
    PythonEngine.PythonPath = $@"{home}\Lib;{home}\Lib\site-packages;{script_path};";
    PythonEngine.Initialize(); // Python ランタイム初期化

    PythonEngine.Initialize();

    using (Py.GIL())
    {
        var sw = Stopwatch.StartNew();

        dynamic pyModule = Py.Import("hello");
        dynamic result = pyModule.greet("パイソン"); // 任意の関数を呼び出し

        sw.Stop();
        Console.WriteLine($"Pythonnet実行時間: {sw.ElapsedMilliseconds} ms");
    }

    PythonEngine.Shutdown();
}

private void ShellCall()
{ 
    var sw = Stopwatch.StartNew();

    var psi = new ProcessStartInfo
    {
        FileName = "python",
        Arguments = "hello.py",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    };

    using var process = Process.Start(psi);
    process.WaitForExit();

    sw.Stop();
    Console.WriteLine($"Shell起動時間: {sw.ElapsedMilliseconds} ms");
}

まとめ

本記事では、C#からPythonの強力なライブラリや関数を直接呼び出すことができる「pythonnet(Python.Runtime)」の活用方法について、具体的なコード例を交えて解説しました。

従来のプロセスコールに比べて、高速かつ柔軟に連携できる点が大きな魅力であり、UIはC#で、データ処理や分析はPythonでといったハイブリッドな開発体制を実現できます。

特に、以下のような方にはpythonnetの導入がお勧めです。

  • Pythonで構築済みのロジックや機械学習モデルを、C#アプリから活用したい方
  • DataTableやList、DictionaryといったC#データを、PythonのpandasやNumPyに自然に橋渡ししたい方
  • 一つのアプリケーションにC#とPythonの利点を統合したい方

また、記事内で紹介した「PythonManager」クラスや「DataTableExtensions」拡張メソッドを活用することで、Pythonとの連携をより簡潔かつ安全に行うことが可能です。

C#とPythonの“いいとこ取り”をしたい開発者にとって、pythonnetは強力な武器となるでしょう。ぜひ、あなたのプロジェクトにも取り入れてみてください!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次