VCへPython組込み動的処理を行う – PyImport_ReloadModule –


C言語とPythonスクリプトを連携させたく、組込んでみたのですが、その際に役に立ったのでURLリストを作成しておきます。

参考サイト

Pythonスクリプトを同的に変更する

まずは、APIの『純粋な埋め込み』を実装してみました。単純なCソースからのPythonスクリプトのコール処理は比較的簡単に実装できました。

ただ、Pythonは1度インタプリタにかけてしまうとメモリ上に残っているので、ソースファイルを修正してもリロードしてくれません。そこで、以下のように修正し、リロード(PyImport_ReloadModule)処理を入れてみました。”end”文字列が入力されるまで繰返しmultiply.pyスクリプトを処理します。

#include <stdio.h>
#include <Python.h>

extern int sub_main(int argc, char *argv[]);
extern char *readfile(char filename[]);

#define PARAMLEN 3
int
main(int argc, char *argv[])
{
	int ret = -1 ;
	char cmd[PARAMLEN][32] = {"call","multiply","multiply"};
	char moji[64];
	argc = PARAMLEN;
	argv[0] = &cmd[0];
	argv[1] = &cmd[1];
	argv[2] = &cmd[2];

	// 初期化
	Py_Initialize();

	while(1){
		ret = sub_main(argc, argv); // multiply.py処理
		printf("----------------------------------\n", ret);
		printf("result is %d\n", ret);
		printf("----------------------------------\n", ret);
		scanf("%s", moji);
		if( 0 == strcmp(moji, "end")) // "end" で終了
			break;
	}
	// 終了処理
	Py_Finalize();

	return ret;
}

int
sub_main(int argc, char *argv[])
{
    PyObject *pName, *pModule, *pDict, *pFunc, *pModule2, *pModulePrm;  // iwakura Add
    PyObject *pArgs, *pValue;
    int i;
	char *p_buf;

    pName = PyString_FromString(argv[1]);

    /* Error checking of pName left out */
    pModule = PyImport_Import(pName);
	pModule2 = PyImport_ReloadModule(pModule); // iwakura Add
    Py_DECREF(pName);

    if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule2, 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);
					Py_DECREF(pModule2); // iwakura Add
                    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);
				Py_DECREF(pModule2); // iwakura Add
                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);
		Py_DECREF(pModule2); // iwakura Add
    }
    else {
        PyErr_Print();
        fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
        return 1;
    }
    return 0;
}

multiply.pyは参考元ソースそのままです。a,bのパラメータを修正すると、動的に処理内容が変更されているのが分かります。

#def multiply(a,b):
def multiply():
    a=2
    b=5
    
    print "Will compute", a, "times", b
    c = 0
    for i in range(0, a):
        c = c + b
    return c