programing

C 코드에서 Python 코드를 어떻게 부릅니까?

prostudy 2022. 4. 29. 23:13
반응형

C 코드에서 Python 코드를 어떻게 부릅니까?

새로운 기능을 가진 큰 C 프로젝트를 확장하고 싶지만, 파이톤으로 꼭 쓰고 싶어.기본적으로 나는 C 코드의 Python 코드를 부르고 싶다.그러나 SWIG와 같은 Python->C 래퍼는 C 모듈을 쓰고 Python에서 C를 호출하는 REVENT를 허용한다.

IPC나 RPC(다중 프로세스를 갖는 것은 개의치 않음)를 포함하는 접근방식을 고려하고 있다. 즉, 내 순수 피톤 구성 요소를 (같은 기계에서) 별도의 프로세스로 실행하고, 내 C 프로젝트가 소켓(또는 유닉스 파이프)에서 쓰기/읽기를 통해 그것과 통신하도록 하는 것이다.내 파이톤 컴포넌트는 소켓을 읽고 쓸 수 있고 통신할 수 있어.그게 합리적인 접근인가?이보다 더 좋은 것은 없을까?특별한 RPC 메커니즘 같은 거?

지금까지 답변해주셔서 감사합니다만, 파이톤 프로그램을 C 프로그램으로 별도 프로세스로 하고 싶기 때문에 IPC 기반 접근법에 집중하고 싶다. 나는 파이톤 통역사를 포함시키고 싶지 않다. 고마워!

나는 여기에 상세히 기술된 접근법을 추천한다.Python 코드의 문자열을 실행하는 방법을 설명하는 것으로 시작되며, 여기서부터 Python 환경을 설정하여 C 프로그램과 상호 작용하는 방법, C 코드에서 Python 함수를 호출하는 방법, C 코드에서 Python 개체를 조작하는 방법 등이 자세히 설명된다.

편집: IPC의 경로로 가고 싶다면, 구조 모듈을 사용하거나 더 나은 방식으로, 양립을 사용하길 원할 것이다.Python과 C 프로세스 사이의 대부분의 통신은 소켓이나 공유 메모리를 통해 구조체를 앞뒤로 전달하는 것에 초점을 맞춘다.

다음 항목을 만들 것을 권장한다.Command명령어와 인수를 나타내는 필드 및 코드가 있는 구조.당신이 이루고자 하는 것이 무엇인지 더 자세히 알지 않고는 훨씬 더 구체적인 충고를 할 수 없지만, 일반적으로 는 양립도서관이 C와 파이톤 프로그램들 사이에서 의사소통할 때 사용하는 것이기 때문에 그것을 추천한다(거절자:나는 양립의 작가다.

셸 스크립트로 파이썬 애플리케이션을 감싸서 C 애플리케이션 내에서 호출하는 것을 고려해 보셨습니까?

가장 우아한 해결책은 아니지만 매우 간단하다.

이것은 꽤 괜찮은 것 같다. 그것에 관한 책도 있다.

세부사항:

The Apache Thrift software framework, for scalable cross-language services development, combines a software stack with a code generation engine to build services that work efficiently and seamlessly between C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi and other languages.

나는 Python을 다른 어플리케이션에 임베딩하는 "표준" 접근법을 사용해 왔다.하지만 그것은 복잡하다/테디하다.Python의 각각의 새로운 기능은 구현하기가 고통스럽다.

C에서 PyPy를 부르는 예를 보았다.인터페이스를 단순화하기 위해 CFFI를 사용하지만 파이썬이 아닌 파이피가 필요하다.적어도 높은 수준에서 이 예를 먼저 읽고 이해하라.

Python과 함께 작업하기 위해 C/PyPy 예제를 수정했다.CFFI를 사용하여 C에서 Python을 호출하는 방법은 다음과 같다.

파이톤에서 한 가지 기능 대신 세 가지 기능을 구현했기 때문에 나의 예는 더욱 복잡하다.나는 자료를 주고받는 것의 추가적인 측면들을 다루고 싶었다.

복잡한 부분은 이제 의 주소지를 통과하기 위해 격리되어 있다.api파이톤으로.그것은 한 번만 시행하면 된다.그 후에는 파이톤에서 새로운 기능을 추가하기 쉽다.

interface.h

// These are the three functions that I implemented in Python.
// Any additional function would be added here.
struct API {
    double (*add_numbers)(double x, double y);
    char* (*dump_buffer)(char *buffer, int buffer_size);
    int (*release_object)(char *obj);
};

test_cffi.c

//
// Calling Python from C.
// Based on Calling PyPy from C:
// http://doc.pypy.org/en/latest/embedding.html#more-complete-example
//

#include <stdio.h>
#include <assert.h>

#include "Python.h"

#include "interface.h"

struct API api;   /* global var */

int main(int argc, char *argv[])
{
    int rc;

    // Start Python interpreter and initialize "api" in interface.py using 
    // old style "Embedding Python in Another Application":
    // https://docs.python.org/2/extending/embedding.html#embedding-python-in-another-application
    PyObject *pName, *pModule, *py_results;
    PyObject *fill_api;
#define PYVERIFY(exp) if ((exp) == 0) { fprintf(stderr, "%s[%d]: ", __FILE__, __LINE__); PyErr_Print(); exit(1); }

    Py_SetProgramName(argv[0]);  /* optional but recommended */
    Py_Initialize();
    PyRun_SimpleString(
            "import sys;"
            "sys.path.insert(0, '.')" );

    PYVERIFY( pName = PyString_FromString("interface") )
    PYVERIFY( pModule = PyImport_Import(pName) )
    Py_DECREF(pName);
    PYVERIFY( fill_api = PyObject_GetAttrString(pModule, "fill_api") )

    // "k" = [unsigned long],
    // see https://docs.python.org/2/c-api/arg.html#c.Py_BuildValue
    PYVERIFY( py_results = PyObject_CallFunction(fill_api, "k", &api) )
    assert(py_results == Py_None);

    // Call Python function from C using cffi.
    printf("sum: %f\n", api.add_numbers(12.3, 45.6));

    // More complex example.
    char buffer[20];
    char * result = api.dump_buffer(buffer, sizeof buffer);
    assert(result != 0);
    printf("buffer: %s\n", result);

    // Let Python perform garbage collection on result now.
    rc = api.release_object(result);
    assert(rc == 0);

    // Close Python interpreter.
    Py_Finalize();

    return 0;
}

접점파이를 치다

import cffi
import sys
import traceback

ffi = cffi.FFI()
ffi.cdef(file('interface.h').read())

# Hold references to objects to prevent garbage collection.
noGCDict = {}

# Add two numbers.
# This function was copied from the PyPy example.
@ffi.callback("double (double, double)")
def add_numbers(x, y):
    return x + y

# Convert input buffer to repr(buffer).
@ffi.callback("char *(char*, int)")
def dump_buffer(buffer, buffer_len):
    try:
        # First attempt to access data in buffer.
        # Using the ffi/lib objects:
        # http://cffi.readthedocs.org/en/latest/using.html#using-the-ffi-lib-objects
        # One char at time, Looks inefficient.
        #data = ''.join([buffer[i] for i in xrange(buffer_len)])

        # Second attempt.
        # FFI Interface:
        # http://cffi.readthedocs.org/en/latest/using.html#ffi-interface
        # Works but doc says "str() gives inconsistent results".
        #data = str( ffi.buffer(buffer, buffer_len) )

        # Convert C buffer to Python str.
        # Doc says [:] is recommended instead of str().
        data = ffi.buffer(buffer, buffer_len)[:]

        # The goal is to return repr(data)
        # but it has to be converted to a C buffer.
        result = ffi.new('char []', repr(data))

        # Save reference to data so it's not freed until released by C program.
        noGCDict[ffi.addressof(result)] = result

        return result
    except:
        print >>sys.stderr, traceback.format_exc()
        return ffi.NULL

# Release object so that Python can reclaim the memory.
@ffi.callback("int (char*)")
def release_object(ptr):
    try:
        del noGCDict[ptr]
        return 0
    except:
        print >>sys.stderr, traceback.format_exc()
        return 1

def fill_api(ptr):
    global api
    api = ffi.cast("struct API*", ptr)

    api.add_numbers = add_numbers
    api.dump_buffer = dump_buffer
    api.release_object = release_object

컴파일:

gcc -o test_cffi test_cffi.c -I/home/jmudd/pgsql-native/Python-2.7.10.install/include/python2.7 -L/home/jmudd/pgsql-native/Python-2.7.10.install/lib -lpython2.7

실행:

$ test_cffi
sum: 57.900000
buffer: 'T\x9e\x04\x08\xa8\x93\xff\xbf]\x86\x04\x08\x00\x00\x00\x00\x00\x00\x00\x00'
$ 

매뉴얼의 관련 장 http://docs.python.org/extending/을 참조하십시오.

기본적으로 당신은 당신의 프로그램에 파이선 통역기를 내장해야 할 것이다.

파이썬 통신에 IPC 방식을 사용하지 않았지만 잘 될 거야.C 프로그램이 표준 포크 실행을 수행하도록 하고 리디렉션됨을 사용함stdin그리고stdout의사소통을 위한 아동 과정 중에훌륭한 텍스트 기반 커뮤니케이션은 파이톤 프로그램을 개발하고 테스트하는 것을 매우 쉽게 만들 것이다.

IPC를 사용하기로 했다면 XML-RPC와 함께 했을 겁니다. 교차 플랫폼으로 나중에 Python 서버 프로젝트를 다른 노드에 쉽게 배치할 수 있고, 우수한 구현이 많음(C와 Python을 비롯한 많은 노드에 대해서는 여기를 참조하고, Python 표준 라이브러리의 일부인 단순 XML-RPC 서버에 대해서는 여기 참조).다른 접근방식으로 확장 가능하지만, 사용 사례에 적합하고 편리할 수 있음).

그것은 모든 경우에 완벽한 IPC 접근법이 아닐 수도 있지만, 편의성, 유연성, 견고성, 그리고 광범위한 구현 범위는 많은 사소한 결함보다 더 크다고 나는 생각한다.

보아하니 Python은 win32 dll로 컴파일할 수 있어야 한다. 그것은 문제를 해결할 것이다.

c# 코드를 win32 dll로 변환하면 모든 개발 도구가 사용할 수 있게 된다.

Python 3으로 바인딩하기 위한 몇 가지 팁

  1. filedmessages가 지원되지 않음, openmessage 사용

ffi.cdef(open('interface.h').read())

  1. PyObject* PyStr_FromString(const char *u)
    Create a PyStr from a UTF-8 encoded null-terminated character buffer.
    Python 2: PyString_FromString
    Python 3: PyUnicode_FromString

다음으로 변경: PYVERIFIY(pName = PyUnicode_FromString("인터페이스") )

  1. 프로그램명
    wchar_t *name = Py_DecodeLocale(argv[0], NULL);
    Py_SetProgramName(name); 
  1. 편찬을 위하여
   gcc cc.c -o cc -I/usr/include/python3.6m -I/usr/include/x86_64-linux-gnu/python3.6m -lpython3.6m
  1. 나는 쓰레기 더미를 도살했다. 어쩌면 그것이 약간의 아이디어를 줄지도 모른다.
def get_prediction(buffer, buffer_len):
    try:
        data = ffi.buffer(buffer, buffer_len)[:]
        result = ffi.new('char []', data)
      
        print('\n I am doing something here here........',data )

        resultA = ffi.new('char []', b"Failed")  ### New message 

        ##noGCDict[ffi.addressof(resultA)] = resultA 
        return resultA
    except:
        print >>sys.stderr, traceback.format_exc()
        return ffi.NULL
} 

도움이 되고 시간을 절약할 수 있기를 바란다.

참조URL: https://stackoverflow.com/questions/1056051/how-do-you-call-python-code-from-c-code

반응형