CSnakes는 Python 코드와 라이브러리를 C#.NET 솔루션에 효율적으로 통합할 수 있게 해주는 강력한 도구입니다
py 파일에 정의된 function 을 C# 에서 직접 호출하여 사용이 가능합니다.
https://github.com/tonybaloney/csnakes
.NET 8과 9 지원: 최신 .NET 버전과 호환됩니다.
Python 3.9-3.13 지원: 다양한 Python 버전을 지원합니다.
크로스 플랫폼: Windows, macOS, Linux에서 사용 가능합니다.
가상 환경 및 C-확장 지원: Python의 가상 환경과 C-확장을 사용할 수 있습니다.
먼저 py 파일이 만들어질 프로젝트를 생성합니다. 클래스라이브러리 프로젝트를 만들고 클래스파일을 하나 추가해 main.py 로 변경합니다
아래와 같이 코드합니다.
def hello_world(name: str) -> str:
return f"Hello, {name}!"
CSnakes.Runtime Nuget package 를 설치합니다.
Console 프로젝트를 만들어서 앞서 만든 PythonLibrary 에 있는 main.py 의 function 를 호출합니다.
먼저 앞서 만들 프로젝트를 참조합니다.
CSnakes.Runtime Nuget package 를 설치합니다.
python 이 필요한데 여기에서는 Nuget 을 이용한 방법을 알아봅니다.
(Nuget 이 아닌 로컬에 설치된 python 경로를 지정해도 됩니다)
python Nuget package 를 설치합니다.
using CSnakes.Runtime;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
// NUGET 패키지 이용
var builder = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
// py 파일이 있는 경로
var home = Path.Join(Path.GetDirectoryName(Environment.ProcessPath));
var venv = Path.Join(home, ".venv");
services
.WithPython()
.WithHome(home)
.WithVirtualEnvironment(venv)
.FromNuGet("3.13.1")
.WithPipInstaller();
});
var app = builder.Build();
var env = app.Services.GetRequiredService<IPythonEnvironment>();
// Python 환경 정보 출력
Console.WriteLine($"Python Version: {env.Version}");
Console.WriteLine(env.Main().HelloWorld("CSnake"));
Console.ReadKey();
HelloWorld 를 F12 로 정의로 가면 아래처럼 main.py 파일이 c# 코드로 변환된 걸 볼수 있습니다.
// <auto-generated/>
#nullable enable
using CSnakes.Runtime;
using CSnakes.Runtime.Python;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection.Metadata;
using Microsoft.Extensions.Logging;
[assembly: MetadataUpdateHandler(typeof(CSnakes.Runtime.MainExtensions))]
namespace CSnakes.Runtime;
public static class MainExtensions
{
private static IMain? instance;
private static ReadOnlySpan<byte> HotReloadHash => "480beb1659a5a7a5a15d4f3b53dcaec1"u8;
public static IMain Main(this IPythonEnvironment env)
{
if (instance is null)
{
instance = new MainInternal(env.Logger);
}
Debug.Assert(!env.IsDisposed());
return instance;
}
public static void UpdateApplication(Type[]? updatedTypes)
{
instance?.ReloadModule();
}
private class MainInternal : IMain
{
private PyObject module;
private readonly ILogger<IPythonEnvironment> logger;
private PyObject __func_hello_world;
internal MainInternal(ILogger<IPythonEnvironment> logger)
{
this.logger = logger;
using (GIL.Acquire())
{
logger.LogDebug("Importing module {ModuleName}", "main");
module = Import.ImportModule("main");
this.__func_hello_world = module.GetAttr("hello_world");
}
}
void IReloadableModuleImport.ReloadModule()
{
logger.LogDebug("Reloading module {ModuleName}", "main");
using (GIL.Acquire())
{
Import.ReloadModule(ref module);
// Dispose old functions
this.__func_hello_world.Dispose();
// Bind to new functions
this.__func_hello_world = module.GetAttr("hello_world");
}
}
public void Dispose()
{
logger.LogDebug("Disposing module {ModuleName}", "main");
this.__func_hello_world.Dispose();
module.Dispose();
}
public string HelloWorld(string name)
{
using (GIL.Acquire())
{
logger.LogDebug("Invoking Python function: {FunctionName}", "hello_world");
PyObject __underlyingPythonFunc = this.__func_hello_world;
using PyObject name_pyObject = PyObject.From(name)!;
using PyObject __result_pyObject = __underlyingPythonFunc.Call(name_pyObject);
return __result_pyObject.As<string>();
}
}
}
}
/// <summary>
/// Represents functions of the Python module <c>main</c>.
/// </summary>
public interface IMain : IReloadableModuleImport
{
/// <summary>
/// Invokes the Python function <c>hello_world</c>:
/// <code><![CDATA[
/// def hello_world(name: str) -> str: ...
/// ]]></code>
/// </summary>
string HelloWorld(string name);
}
실행 결과
CSnakes.Runtime 을 로컬 파이썬/VM 이용하기 (0) | 2025.01.25 |
---|---|
NuGet 패키지 소스 매핑으로 패키지 설치 오류 해결하기 (0) | 2025.01.18 |
LM-Kit.NET 활용하기 (0) | 2024.10.27 |
C# 키보드 후킹하기 (0) | 2024.10.21 |
C# RabbitMQ Management 실행하기 (0) | 2024.10.14 |