C/C++에서 python 메서드를 호출하여 반환 값 추출
C에서 파이톤 모듈에 정의되어 있는 커스텀 함수를 호출하고 싶다.예비 코드가 있는데 출력만 출력하면 돼
mytest.py
import math
def myabs(x):
return math.fabs(x)
test.cpp
#include <Python.h>
int main() {
Py_Initialize();
PyRun_SimpleString("import sys; sys.path.append('.')");
PyRun_SimpleString("import mytest;");
PyRun_SimpleString("print mytest.myabs(2.0)");
Py_Finalize();
return 0;
}
반환 값을 C로 추출하는 방법double
그걸 C에 쓰라고?
앞에서 설명한 것처럼 PyRun_SimpleString을 사용하는 것은 좋지 않은 생각인 것 같다.
C-API에서 제공하는 방법(http://docs.python.org/c-api/))을 반드시 사용해야 한다.
서론을 읽는 것이 그것이 작동하는 방식을 이해하기 위해 가장 먼저 해야 할 일이다.
먼저 C API의 기본 객체인 PyObject에 대해 배워야 한다.그것은 모든 종류의 비단뱀 기본형(끈, 플로트, 끈, 플로트, 인트,...
python 문자열을 char*로 변환하거나 PyFloat를 double로 변환하는 많은 기능이 있다.
먼저 모듈을 가져오십시오.
PyObject* myModuleString = PyString_FromString((char*)"mytest");
PyObject* myModule = PyImport_Import(myModuleString);
그런 다음 기능에 대한 참조를 얻으십시오.
PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"myabs");
PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(2.0));
그런 다음 결과를 얻으십시오.
PyObject* myResult = PyObject_CallObject(myFunction, args)
그리고 다시 2루타로 돌아간다.
double result = PyFloat_AsDouble(myResult);
당신은 분명히 오류(Mark Tollonen이 제공한 cf. 링크)를 확인해야 한다.
궁금한 점이 있으면 주저하지 마라.행운을 빈다.
Python 코드에 문자열을 보낸 다음 값을 반환하기 위해 내가 (여러 온라인 소스의 도움으로) 작성한 샘플 코드 입니다.
여기 C 코드가 있다.call_function.c
:
#include <Python.h>
#include <stdlib.h>
int main()
{
// Set PYTHONPATH TO working directory
setenv("PYTHONPATH",".",1);
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *presult;
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyString_FromString((char*)"arbName");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, (char*)"someFunction");
if (PyCallable_Check(pFunc))
{
pValue=Py_BuildValue("(z)",(char*)"something");
PyErr_Print();
printf("Let's give this a shot!\n");
presult=PyObject_CallObject(pFunc,pValue);
PyErr_Print();
} else
{
PyErr_Print();
}
printf("Result is %d\n",PyInt_AsLong(presult));
Py_DECREF(pValue);
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
return 0;
}
여기 Python 코드가 파일로 되어 있다.arbName.py
:
def someFunction(text):
print 'You passed this Python program '+text+' from C! Congratulations!'
return 12345
나는 명령을 사용한다.gcc call_function.c -I/usr/include/python2.6 -lpython2.6 ; ./a.out
이 과정을 실행하기 위해서.나 레드햇이야.오류 확인에는 Pyerr_Print();를 사용하는 것이 좋다.
Python 함수를 호출하고 결과를 검색하는 전체 예는 http://docs.python.org/release/2.6.5/extending/embedding.html#pure-embedding에 있다.
#include <Python.h>
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
int i;
if (argc < 3) {
fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
return 1;
}
Py_Initialize();
pName = PyString_FromString(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; ++i) {
pValue = PyInt_FromLong(atoi(argv[i + 3]));
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* pValue reference stolen here: */
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL) {
printf("Result of call: %ld\n", PyInt_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
return 1;
}
Py_Finalize();
return 0;
}
다른 답변에서와 같이 .py 파일이 추가되지 않도록 하려면 해당 파일을 검색하십시오.__main__
첫 번째 호출에 의해 생성되는 모듈PyRun_SimpleString
:
PyObject *moduleMainString = PyString_FromString("__main__");
PyObject *moduleMain = PyImport_Import(moduleMainString);
PyRun_SimpleString(
"def mul(a, b): \n"\
" return a * b \n"\
);
PyObject *func = PyObject_GetAttrString(moduleMain, "mul");
PyObject *args = PyTuple_Pack(2, PyFloat_FromDouble(3.0), PyFloat_FromDouble(4.0));
PyObject *result = PyObject_CallObject(func, args);
printf("mul(3,4): %.2f\n", PyFloat_AsDouble(result)); // 12
어떻게든 파이톤 방법을 추출해 가지고 실행해야 한다.PyObject_CallObject()
. 이를 위해 Extending and Embedding Python Tutorial의 예처럼 기능을 설정할 수 있는 방법을 Python에 제공하십시오.
변수에 반환 값을 할당하면 PyEval_GetGlobals()와 PyDict_GetItemString() 같은 것을 사용하여 PyObject를 가져올 수 있다.거기서 PyNumber_Float는 당신이 원하는 값을 얻을 수 있다.
나는 API 전체를 살펴볼 것을 제안한다. 당신이 이용할 수 있는 다른 방법들을 볼 때, 어떤 것들은 명백해지고, 내가 설명한 방법보다 더 나은 방법이 있을 것이다.
나는 BUX를 사용하여 Python에서 C++로 임베디드한 적이 있다 [이 작업 C 모듈이 도움이 될 것이다]
#include <boost/python.hpp>
void main()
{
using namespace boost::python;
Py_Initialize();
PyObject* filename = PyString_FromString((char*)"memory_leak_test");
PyObject* imp = PyImport_Import(filename);
PyObject* func = PyObject_GetAttrString(imp,(char*)"begin");
PyObject* args = PyTuple_Pack(1,PyString_FromString("CacheSetup"));
PyObject* retured_value = PyObject_CallObject(func, args); // if you have arg
double retured_value = PyFloat_AsDouble(myResult);
std::cout << result << std::endl;
Py_Finalize();
}
다음은 질문에 대한 간단하고 직접적인 대답이다.
#include <iostream>
#include <Python.h>
using namespace std;
int main()
{
const char *scriptDirectoryName = "/yourDir";
Py_Initialize();
PyObject *sysPath = PySys_GetObject("path");
PyObject *path = PyString_FromString(scriptDirectoryName);
int result = PyList_Insert(sysPath, 0, path);
PyObject *pModule = PyImport_ImportModule("mytest");
PyObject* myFunction = PyObject_GetAttrString(pModule,(char*)"myabs");
PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(-2.0));
PyObject* myResult = PyObject_CallObject(myFunction, args);
double getResult = PyFloat_AsDouble(myResult);
return 0;
}
다음은 Python 3과 함께 작동하는 최소 실행 버전(Python 2.7 및 3.9와 함께 테스트됨)이다.
문서에 포함된 링크는 설명에 포함되지만 https://docs.python.org/3/c-api/에서 모두 액세스할 수 있다.
#include <Python.h>
#include <stdio.h>
int main()
{
// Initialize the Python Interpreter
Py_Initialize();
// see https://docs.python.org/3/c-api/structures.html
// NULL objects are special and Py_CLEAR knows this
PyObject *module = NULL, *result = NULL;
// https://docs.python.org/3/c-api/import.html
module = PyImport_ImportModule("mytest");
if (!module) {
// Python generally uses exceptions to indicate an error state which
// gets flagged in the C-API (a NULL pointer in this case) indicating
// "something" failed. the PyErr_* API should be used to get more
// details
goto done;
}
// see https://docs.python.org/3/c-api/call.html#c.PyObject_CallMethod
// and https://docs.python.org/3/c-api/arg.html#building-values
result = PyObject_CallMethod(module, "myabs", "f", 3.14);
if (!result) {
goto done;
}
// make sure we got our number back
if (PyFloat_Check(result)) {
printf("Successfully got a float: %f\n", PyFloat_AsDouble(result));
} else {
printf("Successfully got something unexpected!\n");
}
done:
// see https://docs.python.org/3/c-api/exceptions.html
PyErr_Print();
// see https://docs.python.org/3/c-api/refcounting.html
Py_CLEAR(result);
Py_CLEAR(module);
// Optionally release Python Interpreter
Py_Finalize();
return 0;
}
OP의 Python 코드를 사용하는 경우mytest.py
또는 이 한 줄에 해당하는 경우:
from math import fabs as myabs
빌딩은 OS/Python 버전에 따라 다르겠지만, 나에게는 다음과 같은 것이 통한다.
cc -o test -I/usr/include/python3.9 /usr/lib/libpython3.9.so test.c
다른 사람들이 이미 언급했듯이, 이것은 파이톤 문서들에서 대답된다.하지만, 나는 파이톤에서 왔고 C/C++를 사용한 경험이 많지 않기 때문에 파이톤 3에서 실행하는 데 문제가 있었어.여기 다른 스택오버플로우 게시물에서 시간을 보낸 후 Python 문서를 실행하기 위한 전체 작업 예제가 있다.
파일c_function.c
#define PY_SSIZE_T_CLEAN
#include <Python.h>
int main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
int i;
if (argc < 3) {
fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
return 1;
}
Py_Initialize();
// I had to add the following two lines to make it work
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\".\")");
pName = PyUnicode_DecodeFSDefault(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; ++i) {
pValue = PyLong_FromLong(atoi(argv[i + 3]));
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* pValue reference stolen here: */
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL) {
printf("Result of call: %ld\n", PyLong_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
return 1;
}
if (Py_FinalizeEx() < 0) {
return 120;
}
return 0;
}
파일multiply.py
def multiply(a,b):
print("Will compute", a, "times", b)
c = 0
for i in range(0, a):
c = c + b
return c
우리는 그것을 컴파일하고 연결시킬 필요가 있다.이 작업은 다음 명령을 사용하여 수행할 수 있다.
gcc c_function.c -c $(python3.6-config --cflags) -fPIC
그 뒤를 이어
gcc c_function.o $(python3.6-config --ldflags) -o call
예를 들어, Python 3.6의 예후에 Python 문서들의 예들은 단지 다음에 의해 실행될 수 있다.
./call multiply multiply 3 2
'programing' 카테고리의 다른 글
지나가는 부모들의 소품들이 Vue,js. (0) | 2022.05.01 |
---|---|
버퍼링된 이미지를 파일로 저장하는 방법 (0) | 2022.05.01 |
Vue.js: 구성 요소가 초기화될 때 감시기 기능을 작동시키는 방법 (0) | 2022.05.01 |
TypeScript가 Vue 플러그인에 대한 모듈 확장을 인식하지 못하는 이유 (0) | 2022.05.01 |
죄에 대한 정의되지 않은 참조 (0) | 2022.05.01 |