CPython
Hello world
#include <Python.h>
int main(int argc, char** argv)
{
Py_SetProgramName(argv[0]);
Py_Initialize();
PyRun_SimpleString("print \'Hello, World!\'\n");
Py_Finalize();
return 0;
}
Windows의 경우 확장자를 *.dll
가 아닌 *.pyd
로 해야 한다.
Call Function
#include <Python.h>
int main(int argc, char** argv)
{
int i;
PyObject *pModule, *pFunc;
PyObject *pArgs, *pValue;
if (argc < 3) {
fprintf(stderr, "Usage: call.out pythonfile function [args]\n");
return 1;
}
Py_SetProgramName(argv[0]);
Py_Initialize();
/* modified part */
PyRun_SimpleString(
"import sys\n"
"sys.path.append('.')\n");
pModule = PyImport_ImportModule(argv[1]);
pFunc = PyObject_GetAttrString(pModule, argv[2]);
pArgs = PyTuple_New(argc - 3);
for(i = 0; i < argc - 3; ++i) {
pValue = PyInt_FromLong(atoi(argv[i+3]));
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
printf("Result of call: %ld\n", PyInt_AsLong(pValue));
Py_DECREF(pArgs);
Py_DECREF(pValue);
Py_DECREF(pFunc);
Py_DECREF(pModule);
Py_Finalize();
return 0;
}
Create Module
// Pulls in the Python API
#include <Python.h>
static PyObject * spam_system(PyObject *self, PyObject *args) {
/*
PyObject *self: Only be used if building a class method, this would be NULL since it's not a method.
PyObject *args: Pointer to a Python tuple object containing the arguments it'll be passed.
Python expression to be run: spam.system(string)
*/
const char *command;
int sts;
/*
PyArg_ParseTuple: Returns true if all arguments have the right type (and raises appropriate exception otherwise)
"s": Convert a Python string to a C pointer to a character string.
See: http://www.fnal.gov/docs/products/python/v1_5_2/ext/parseTuple.html
*/
if (! PyArg_ParseTuple(args, "s", &command)) {
return NULL;
}
// C command
// See: http://www.thinkage.ca/english/gcos/expl/c/lib/system.html
sts = system(command);
/*
Reverse of ParseTuple, converts it back to something Python
"i" is an integer; system() returns an int
See: http://www.fnal.gov/docs/products/python/v1_5_2/ext/buildValue.html
*/
return Py_BuildValue("i", sts);
}
// Module's method table and initialization function
// See: http://docs.python.org/extending/extending.html#the-module-s-method-table-and-initialization-function
static PyMethodDef SpamMethods[] = {
{"system", spam_system, METH_VARARGS, "Execute a shell command."},
{NULL, NULL, 0, NULL}
};
void initspam(void) {
// Module's initialization function
// Will be called again if you use Python's reload()
PyImport_AddModule("spam");
Py_InitModule("spam", SpamMethods);
}
int main(int argc, char *argv[]) {
Py_SetProgramName(argv[0]);
Py_Initialize();
initspam();
return 0;
}
setup.py
를 작성한다.
from distutils.core import setup, Extension
ext = Extension('spam', sources=['spammodule.c'])
setup(name='foo', version='1.0', description='Test description', ext_modules=[ext])
아래와 같이 BUILD & INSTALL 진행이 가능하다.
Append module path
- PYTHONPATH and embedding python
- Stackoverflow - Is it possible to modify PYTHONPATH at runtime?
- Stackoverflow - Embedding Python in C: Having problems importing local modules
#include "Python.h"
int main()
{
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\"<some_path>\")");
return 0;
}
위 방법은 추가되는 문자열이 Encoding에 영향을 받는다.
Python스크립트 없이 C함수로 적용하는 방법은 아래와 같다.
std::string NEW_PATH = std::string(Py_GetPath()) + PATH_SPLITTER + path;
PySys_SetPath(&NEW_PATH[0]);
이 방법은 정상적으로 적용되지 않는다.
PyObject * sys_module = PyImport_ImportModule("sys");
PyObject * python_path = PyObject_GetAttrString(sys_module, "path");
/* Unicode: */ PyList_Append(python_path, PyUnicode_FromString("."));
// OR:
/* C String: */ PyList_Append(python_path, PyString_FromString(path.c_str()));
Python interpreter code
/* Minimal main program -- everything is loaded from the library */
#include "Python.h"
#include <locale.h>
#ifdef __FreeBSD__
#include <fenv.h>
#endif
#ifdef MS_WINDOWS
int
wmain(int argc, wchar_t **argv)
{
return Py_Main(argc, argv);
}
#else
int
main(int argc, char **argv)
{
wchar_t **argv_copy;
/* We need a second copy, as Python might modify the first one. */
wchar_t **argv_copy2;
int i, res;
char *oldloc;
/* Force malloc() allocator to bootstrap Python */
(void)_PyMem_SetupAllocators("malloc");
argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1));
argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1));
if (!argv_copy || !argv_copy2) {
fprintf(stderr, "out of memory\n");
return 1;
}
/* 754 requires that FP exceptions run in "no stop" mode by default,
* and until C vendors implement C99's ways to control FP exceptions,
* Python requires non-stop mode. Alas, some platforms enable FP
* exceptions by default. Here we disable them.
*/
#ifdef __FreeBSD__
fedisableexcept(FE_OVERFLOW);
#endif
oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL));
if (!oldloc) {
fprintf(stderr, "out of memory\n");
return 1;
}
setlocale(LC_ALL, "");
for (i = 0; i < argc; i++) {
argv_copy[i] = Py_DecodeLocale(argv[i], NULL);
if (!argv_copy[i]) {
PyMem_RawFree(oldloc);
fprintf(stderr, "Fatal Python error: "
"unable to decode the command line argument #%i\n",
i + 1);
return 1;
}
argv_copy2[i] = argv_copy[i];
}
argv_copy2[argc] = argv_copy[argc] = NULL;
setlocale(LC_ALL, oldloc);
PyMem_RawFree(oldloc);
res = Py_Main(argc, argv_copy);
/* Force again malloc() allocator to release memory blocks allocated
before Py_Main() */
(void)_PyMem_SetupAllocators("malloc");
for (i = 0; i < argc; i++) {
PyMem_RawFree(argv_copy2[i]);
}
PyMem_RawFree(argv_copy);
PyMem_RawFree(argv_copy2);
return res;
}
#endif
Multiprocessing Tip
Libraries
C/C++을 사용한 Python포팅 라이브러리는 아래와 같다.
- Boost.Python
- pybind11: https://pybind11.readthedocs.io/en/latest/
- python2cpp: https://github.com/nicodjimenez/python2cpp
- SWIG
See also
- Python
- Cv::Mat:Python: cv::Mat와 OpenCV-Python에서 사용하는 NumPy Array와 호환 시키는 방법.
- HPy - 파이썬을 위한 더 나은 C API
Favorite site
- 1. Extending Python with C or C++
- [추천] ChangwooWiki - Embedded Python 1
- [추천] EmbeddingPythonTutorial
- [추천] Coding Patterns for Python Extensions
- CodeProject: Embedding Python in C/C++: Part I
- [추천] Reference Counting in Python 2
- Embedding Python – Tutorial – Part 1 3
- Joohyun's BLOG :: Boost Python 환경 구축 및 사용예제(Visual Studio 2013 Express 사용)
- [추천] eunguru - C/C++와 연동 4
Tutorials
- Python embedding 1 - Overview 5
- Python embedding 2 - Calling Python function from C/C++ Appilcation 6
- Python embedding 3 - 캐싱 된 모듈 다시 로드 하기 7
- Python embedding 4 - PyErr_Print() 를 파일로 남기기 8
Guide
Article
- [추천] 파이썬이 메모리를 관리하는 방법 10
Documentation Python 3.x
Documentation Python 2.x
- 5. Embedding Python in Another Application
- Documentation » Python/C API Reference Manual » Abstract Objects Layer » Object Protocol
- 1.2.1.1 Reference Count Details
References
-
ChangwooWiki_-_Embedded_Python.pdf ↩
-
Reference_Counting_in_Python.pdf ↩
-
Embedding_Python_-Tutorial-Part_1-_realmike.pdf ↩
-
Eunguru.tistory.com_-_python_and_cpp.pdf ↩
-
Python_embedding_1.pdf ↩
-
Python_embedding_2.pdf ↩
-
Python_embedding_3.pdf ↩
-
Python_embedding_4.pdf ↩
-
Gpg_python_script.pdf ↩
-
How_Python_manages_memory_-_seonghyeon.dev.pdf ↩