मैंने Embedding Python in Another Application के "मानक" दृष्टिकोण का उपयोग किया है। लेकिन यह जटिल/थकाऊ है। पाइथन में प्रत्येक नया कार्य लागू करने के लिए दर्दनाक है।
मैंने Calling PyPy from C का एक उदाहरण देखा। यह इंटरफेस को सरल बनाने के लिए सीएफएफआई का उपयोग करता है लेकिन इसे पायपी की आवश्यकता नहीं है, पाइथन। कम से कम एक उच्च स्तर पर, पहले इस उदाहरण को पढ़ें और समझें।
मैंने पायथन के साथ काम करने के लिए सी/पीईपीई उदाहरण को संशोधित किया। सीएफएफआई का उपयोग कर सी से पायथन को कॉल करने का तरीका यहां दिया गया है।
मेरा उदाहरण अधिक जटिल है क्योंकि मैंने एक के बजाय पायथन में तीन कार्यों को लागू किया है। मैं आगे और आगे डेटा पास करने के अतिरिक्त पहलुओं को कवर करना चाहता था।
जटिल भाग अब 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;
}
interface.py
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
,210
निष्पादित करें:
$ 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'
$
एक अलग प्रक्रिया में अजगर कार्यक्रम डाल करने के लिए इच्छुक है, और एक अजगर दुभाषिया एम्बेड करने के लिए नहीं चाहते के लिए अपने तर्क क्या है? मैं उत्सुक हूँ। –
ठीक है अगर वह पाइथन के लिए केवल पाइपिंग तारों के साथ एक रास्ता प्राप्त कर सकता है और फिर जब इसे पूरा किया जाता है तो उसे वापस पाइथन दुभाषिया एम्बेड करने से बहुत आसान लगता है। इंटरफ़ेस सरल है (बस स्ट्रिंग्स और तारों को पार करते हैं) को बस एक अलग पायथन ऐप को कॉल करने के लिए 5 मिनट के एकीकरण की आवश्यकता होगी और मुझे यकीन है कि एक दुभाषिया को एम्बेड करने में 5 मिनट से अधिक समय लगेगा – hhafez
यहां एक पूर्ण उदाहरण https: // स्टैक ओवरफ़्लो।कॉम/ए/46441794/5842403 जहां आप सी में एम्बेडेड पायथन देख सकते हैं, और फिर सीपीआई का उपयोग कर Systemverilog में एम्बेडेड सी। – Joniale