Programming/C++

파이썬을 사용해보자!

Teemol 2020. 4. 4. 19:59

안녕하세요.  Teemol입니다.

오늘은 C++에서 Python을 사용하는 방법입니다.

 

먼저 아래의 링크에서 Python을 설치해야 합니다.

>>>PYTHON<<<

 

Downloads 탭에서 원하는 버전 / 플랫폼의 Installer를 받아서 설치합니다.

저는 Python 3.7.7 / Window x86 executable installer를 다운로드해서 진행하도록 하겠습니다.

 

설치 시 Customize installation에서 Download debug binaries를 체크하고 진행합니다.

*이 설정으로 디버그에서 사용하는 라이브러리를 받을 수 있습니다.

 

파이썬의 기본 설치 경로는 아래와 같습니다.

 C:\Users\{User}\AppData\Local\Programs\Python

저는 아래와 같은 경로에 설치되었습니다.

C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32

경로를 확인하는 이유는 헤더와 라이브러리를 가져오기 위해서입니다.

 

Python을 사용할 C++ 프로젝트에서 위의 경로에 있는 include 폴더와 libs 폴더를 각각 포함 디렉터리와 라이브러리 디렉터리에 추가합니다.

ex)
	포함 디렉터리 > C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\include
	라이브러리 디렉터리 > C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\libs

그리고 링커 > 입력 > 추가 종속성에 python37.lib를 추가합니다.

*버전에 따라 .lib 명이 다를 수 있습니다.

 

이제 프로젝트에 python37.dllpython37_d.dll을 추가합니다.

*버전에 따라 .dll 명이 다를 수 있습니다.

 

이제 Python을 사용할 수 있습니다.

 

Python을 사용 시 아래의 내용을 추가하고 사용해야 합니다.

그렇지 않으면 Debug에서 제대로 동작하지 않을 수 있습니다.

#define HAVE_ROUND
#ifdef _DEBUG
#define RESTORE_DEBUG
#undef _DEBUG
#endif
#include <Python.h>
#ifdef RESTORE_DEBUG
#define _DEBUG
#undef RESTORE_DEBUG
#endif

 

간단한 예제를 만들어 보겠습니다.

 

예제 1. 아래의 코드는 C++에서 Python의 함수를 호출하는 내용입니다.

더보기

CPP CODE

    PyObject* module_name, * module, * pFunc;

    Py_Initialize();

    module_name = PyUnicode_FromString("Sample");

    module = PyImport_Import(module_name);
    if (module == nullptr) {
        PyErr_Print();
        std::cerr << "Fails to import the module.\n";
        return 1;
    }
    Py_DECREF(module_name);

    pFunc = PyObject_GetAttrString(module, "Function");
    Py_DECREF(module);

    PyObject_CallObject(pFunc, nullptr);
    Py_DECREF(pFunc);
 
    Py_Finalize();

PYTHON CODE (Sample.py)

def Function():
 print("Hello Python!")

 

예제 2. 아래의 코드는 C++에서 Python의 Sample 클래스 안에 있는 함수인 두 개의 숫자를 받고 두 값을 더해서 돌려주는 함수를 호출하는 내용입니다.

더보기

CPP CODE

    PyObject* module_name, * module, * dict, * python_class, * object, * args, * func;

    Py_Initialize();
    module_name = PyUnicode_FromString("Sample2");

    module = PyImport_Import(module_name);
    if (module == nullptr) {
        PyErr_Print();
        return 1;
    }
    Py_DECREF(module_name);

    dict = PyModule_GetDict(module);
    if (dict == nullptr) {
        PyErr_Print();
        return 1;
    }
    Py_DECREF(module);

    python_class = PyDict_GetItemString(dict, "Sample");
    if (python_class == nullptr) {
        PyErr_Print();
        return 1;
    }
    Py_DECREF(dict);

    if (PyCallable_Check(python_class)) {
        object = PyObject_CallObject(python_class, nullptr);
        Py_DECREF(python_class);
    }
    else {
        Py_DECREF(python_class);
        return 1;
    }

    func = PyObject_GetAttrString(object, "Sum");
    Py_DECREF(object);

    args = PyTuple_New(2);
    PyTuple_SetItem(args, 0, PyLong_FromLong(1));
    PyTuple_SetItem(args, 1, PyLong_FromLong(2));

    PyObject* value = PyObject_CallObject(func, args);
    Py_DECREF(args);
    Py_DECREF(func);

    long result = PyLong_AsLong(value);
	Py_DECREF(value);
    
    Py_Finalize();

PYTHON CODE (Sample2.py)

class Sample:
 def Sum(self, num1, num2):
  return ( num1 + num2 )

 

함수의 첫 번째 인자 self는 아래와 같은 방식으로 사용하지 않을 수 있습니다.

class Sample:
 @staticmethod
 def Sum(num1, num2):
  return ( num1 + num2 )

 

마지막으로 Python을 포함해서 배포하는 방법입니다.

Python Installer를 받은 곳에서 embeddable zip file을 다운로드합니다.

ex) Windows x86 embeddable zip file

해당 파일을 받아서 압축을 풀면 또 하나의 .zip 파일이 있습니다.

저는 python37.zip 파일이 있습니다.

*버전에 따라 .zip 명이 다를 수 있습니다.

 

python37.zip 파일을 배포할 응용프로그램이 있는 폴더로 이동 후 Python을 사용하는 코드의 시작 부분에 아래의 내용을 추가합니다.

    //ADD
    Py_SetPythonHome(L"python37");

    Py_Initialize();
    module_name = PyUnicode_FromString("Sample2");

SetPythonHome(L"python37")을 추가하였습니다.

 

위 내용을 추가하고 빌드 한 뒤 응용프로그램을 배포할 때 python37.zip을 같이 배포하면 Python이 설치되어 있지 않아도 Python을 사용할 수 있습니다.

 

*주의사항

Python 파일명이 Lib에 있는 파일명과 동일하면 Lib의 내용을 먼저 읽어서 제대로 동작하지 않습니다.

 ex) test.py, abc.py 등

 

- 끄읕