Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일

C# - Python.NET의 RunSimpleScript, Exec, Eval 차이점

Python.NET을 사용하는 경우,

C# - Python.NET을 이용한 파이썬 소스코드 연동
; https://www.sysnet.pe.kr/2/0/13605

스크립트 실행 방식이 4가지가 있습니다. 우선 (deprecated로 표시된) RunString이 있는데요,

using Python.Runtime;

internal class Program
{
    // Install-Package pythonnet
    static void Main(string[] args)
    {
        string script = File.ReadAllText("test.py");

        Runtime.PythonDLL = @"E:\Python3133\embed\python313.dll";
        PythonEngine.Initialize();

        PyDict globalDict = new PyDict();
        PyDict localDict = new PyDict();

        using (_ = Py.GIL())
        {
            PythonEngine.RunString(script, globalDict, localDict);
        }

        PythonEngine.Shutdown();
    }
}

현재는 RunSimpleString이 그 역할을 이어가고 있습니다.

// PythonEngine.RunString(script, globalDict, localDict);

PythonEngine.RunSimpleString(script);

차이점이라면 global dict와 local dict를 사용할 수 없다는 건데요, 이게 필요하다면 Exec 버전을 사용하면 됩니다. 예를 들어, 파이썬 소스 코드가 다음과 같을 때,

print('test')

def my_func(a, b):
    return a + b

Exec 버전을 사용하면,

PythonEngine.Exec(script, globalDict, localDict); // 화면에 "test" 출력
dynamic my_func = localDict.GetItem("my_func");
Console.WriteLine(my_func(5, 6)); // 출력: 11

해당 스크립트가 실행되면서 함께 전달했던 globalDict/localDict로 파이썬 스크립트 내부의 개체와 연동할 수 있습니다





RunSimpleString과 Exec에는 또 다른 차이점이 하나 더 존재하는데요, 예를 들어, 아래의 코드는 python으로 실행 시, 또는 PythonEngine.RunSimpleString으로 실행하면 정상적으로 작동하지만,

C:\temp> type test.py

import os


def get_current_dir():
    return os.getcwd()


print('getcwd:', get_current_dir())


C:\temp> python test.py
getcwd: C:\temp

PythonEngine.Exec을 통해 실행하면 이런 오류가 발생합니다.

PythonEngine.Exec(script, globalDict, localDict);

/*
Unhandled exception. Python.Runtime.PythonException: name 'os' is not defined
  File "<string>", line 6, in get_current_dir
  File "<string>", line 9, in <module>
   at Python.Runtime.PythonException.ThrowLastAsClrException()
   at Python.Runtime.PythonException.ThrowIfIsNull(NewReference& ob)
   at Python.Runtime.PythonEngine.RunString(String code, BorrowedReference globals, BorrowedReference locals, RunFlagType flag)
   at Python.Runtime.PythonEngine.Exec(String code, PyDict globals, PyObject locals)
   at Program.Main(String[] args) in C:\temp\ConsoleApp1\ConsoleApp1\Program.cs:line 34
*/

재미있는 건, Exec의 경우에도 PyDict(globa/local)를 넘기지 않는다면 정상적으로 실행이 됩니다.

PythonEngine.Exec(script); // "name '...' is not defined" 오류 없이 정상적으로 실행됨

이게 의도한 것인지, 버그인지는 잘 모르겠습니다. 만약 Exec의 버전에서 꼭 PyDict(globa/local) 문맥이 필요하다면 파이썬 소스 코드를 이런 식으로 수정하거나,

import os


def get_current_dir():
    global os
    return os.getcwd()


print('getcwd:', get_current_dir())

아예 import를 get_current_dir 함수 내에서 하면 됩니다.

def get_current_dir():
    import os
    return os.getcwd()




마지막으로 Exec와 Eval의 차이점은 파이썬 본래의 exec/eval과 유사합니다. Exec의 경우 반환값이 없는 메서드이면서 스크립트에 문(statement)을 포함할 수 있는데요, 반면 Eval은 스크립트에 "식(expression)"만 포함할 수 있지만 대신 그 식의 평가값을 메서드가 반환합니다.

Console.WriteLine(PythonEngine.Eval("5 + 6")); // 출력: 11

또한 Exec처럼 globalDict/localDict를 사용할 수 있기 때문에 문맥을 공유해 실행하는 것도 가능합니다.

/* # script.py
def my_func(a, b):
    return a + b
*/
PythonEngine.Exec(script, globalDict, localDict); // Exec로 실행된 환경의 global/local 문맥으로,

// Eval 함수에서 재사용
var retValue = PythonEngine.Eval("my_func(5, 6)", globalDict, localDict);
Console.WriteLine(retValue); // 출력: 11




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 5/5/2025]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 91  92  93  94  [95]  96  97  98  99  100  101  102  103  104  105  ...
NoWriterDateCnt.TitleFile(s)
11560정성태6/25/201821597.NET Framework: 776. C# 7.3 - 초기화 식에서 변수 사용 가능(expression variables in initializers)파일 다운로드1
11559정성태6/25/201828677개발 환경 구성: 384. 영문 설정의 Windows 10 명령행 창(cmd.exe)의 한글 지원 [6]
11558정성태6/24/201822326.NET Framework: 775. C# 7.3 - unmanaged(blittable) 제네릭 제약파일 다운로드1
11557정성태6/22/201821804.NET Framework: 774. C# - blittable 타입이란?파일 다운로드1
11556정성태6/19/201828710.NET Framework: 773. C# 7.3 - 구조체의 고정 크기를 갖는 fixed 배열 필드에 대한 직접 접근 가능 [1]파일 다운로드1
11555정성태6/18/201820392.NET Framework: 772. C# 7.3 - 사용자 정의 타입에 fixed 적용 가능(Custom fixed)파일 다운로드1
11554정성태6/17/201822369.NET Framework: 771. C# 7.3 - 자동 구현 속성에 특성 적용 가능(Attribute on backing field)
11553정성태6/15/201821978.NET Framework: 770. C# 7.3 - 개선된 메서드 선택 규칙 3가지(Improved overload candidates)파일 다운로드1
11552정성태6/15/201823929.NET Framework: 769. C# 7.3에서 개선된 문법 4개(Support == and != for tuples, Ref Reassignment, Constraints, Stackalloc initializers)파일 다운로드1
11551정성태6/14/201820567개발 환경 구성: 383. BenchmarkDotNet 사용 시 주의 사항
11550정성태6/13/201820462.NET Framework: 768. BenchmarkDotNet으로 Span<T> 성능 측정 [2]
11549정성태6/13/201822137개발 환경 구성: 382. BenchmarkDotNet에서 생성한 BuildPlots.R 파일을 실행하는 방법
11548정성태6/13/201819307오류 유형: 470. .NET Core + BenchmarkDotNet 실행 시 프레임워크를 찾지 못하는 문제
11547정성태6/13/201824550.NET Framework: 767. BenchmarkDotNet 라이브러리 소개파일 다운로드1
11546정성태6/12/201824568.NET Framework: 766. C# 7.2의 특징 - GC 및 메모리 복사 방지를 위한 struct 타입 개선 [9]파일 다운로드1
11545정성태6/11/201822835오류 유형: 469. .NET Core 프로젝트를 Visual Studio에서 실행 시 System.BadImageFormatException 발생하는 경우 [1]
11544정성태6/10/201822407.NET Framework: 765. C# 7.2 - 숫자 리터럴의 선행 밑줄과 뒤에 오지 않는 명명된 인수
11543정성태6/9/201821988.NET Framework: 764. C# 7.2 - private protected 접근자 추가파일 다운로드1
11542정성태6/9/201860425개발 환경 구성: 381. Azure Web App 확장 예제 - Remove Custom Headers
11541정성태6/9/201819554개발 환경 구성: 380. Azure Web App 확장 배포 방법 [1]
11540정성태6/9/201820304개발 환경 구성: 379. Azure Web App 확장 예제 제작 [2]
11539정성태6/8/201820246.NET Framework: 763. .NET Core 2.1 - Tiered Compilation 도입파일 다운로드1
11538정성태6/8/201819426.NET Framework: 762. .NET Core 2.1 - 확장 도구(Tools) 관리 [1]
11537정성태6/8/201823952.NET Framework: 761. C# - SmtpClient로 SMTP + SSL/TLS 서버를 이용하는 방법 [5]
11536정성태6/7/201821610.NET Framework: 760. Microsoft Build 2018 - The future of C# 동영상 내용 정리 [1]파일 다운로드1
11535정성태6/7/201823423.NET Framework: 759. C# - System.Span<T> 성능 [1]
... 91  92  93  94  [95]  96  97  98  99  100  101  102  103  104  105  ...