Hướng dẫn message passing in python - gửi tin nhắn trong python

Các chương trước đã thảo luận về cách mở rộng Python, nghĩa là làm thế nào để mở rộng chức năng của Python bằng cách đính kèm một thư viện các chức năng C với nó. Cũng có thể làm theo cách khác: làm phong phú ứng dụng C/C ++ của bạn bằng cách nhúng python vào đó. Nhúng cung cấp cho ứng dụng của bạn khả năng thực hiện một số chức năng của ứng dụng của bạn trong Python thay vì C hoặc C ++. Điều này có thể được sử dụng cho nhiều mục đích; Một ví dụ sẽ là cho phép người dùng điều chỉnh ứng dụng theo nhu cầu của họ bằng cách viết một số tập lệnh bằng Python. Bạn cũng có thể tự mình sử dụng nó nếu một số chức năng có thể được viết bằng Python dễ dàng hơn.

Nhúng Python tương tự như mở rộng nó, nhưng không hoàn toàn. Sự khác biệt là khi bạn mở rộng Python, chương trình chính của ứng dụng vẫn là phiên dịch Python, trong khi nếu bạn nhúng Python, chương trình chính có thể không liên quan gì đến Python - thay vào đó, một số phần của ứng dụng thỉnh thoảng gọi Để chạy một số mã python.

Vì vậy, nếu bạn đang nhúng Python, bạn đang cung cấp chương trình chính của riêng bạn. Một trong những điều mà chương trình chính này phải làm là khởi tạo trình thông dịch Python. Ít nhất, bạn phải gọi hàm

#define PY_SSIZE_T_CLEAN
#include 

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();
    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;
}
3. Có các cuộc gọi tùy chọn để vượt qua các đối số dòng lệnh đến Python. Sau đó, bạn có thể gọi trình thông dịch từ bất kỳ phần nào của ứng dụng.

Có một số cách khác nhau để gọi trình thông dịch: bạn có thể chuyển một chuỗi chứa các câu lệnh Python sang

#define PY_SSIZE_T_CLEAN
#include 

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();
    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;
}
4 hoặc bạn có thể chuyển một con trỏ tệp stdio và tên tệp (chỉ để nhận dạng trong thông báo lỗi) sang
#define PY_SSIZE_T_CLEAN
#include 

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();
    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;
}
5. Bạn cũng có thể gọi các hoạt động cấp thấp hơn được mô tả trong các chương trước để xây dựng và sử dụng các đối tượng Python.

Xem thêm

Hướng dẫn tham khảo API Python/C

Các chi tiết về giao diện Python sườn C được đưa ra trong hướng dẫn này. Rất nhiều thông tin cần thiết có thể được tìm thấy ở đây.

1.1. Mức độ nhúng rất caoVery High Level Embedding¶

Hình thức đơn giản nhất của việc nhúng python là việc sử dụng giao diện cấp độ rất cao. Giao diện này nhằm thực hiện tập lệnh Python mà không cần phải tương tác trực tiếp với ứng dụng. Điều này ví dụ có thể được sử dụng để thực hiện một số hoạt động trên một tệp.

#define PY_SSIZE_T_CLEAN
#include 

int
main(int argc, char *argv[])
{
    wchar_t *program = Py_DecodeLocale(argv[0], NULL);
    if (program == NULL) {
        fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
        exit(1);
    }
    Py_SetProgramName(program);  /* optional but recommended */
    Py_Initialize();
    PyRun_SimpleString("from time import time,ctime\n"
                       "print('Today is', ctime(time()))\n");
    if (Py_FinalizeEx() < 0) {
        exit(120);
    }
    PyMem_RawFree(program);
    return 0;
}

Hàm

#define PY_SSIZE_T_CLEAN
#include 

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();
    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;
}
6 nên được gọi trước
#define PY_SSIZE_T_CLEAN
#include 

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();
    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;
}
3 để thông báo cho người phiên dịch về các đường dẫn đến các thư viện thời gian chạy Python. Tiếp theo, trình thông dịch Python được khởi tạo với
#define PY_SSIZE_T_CLEAN
#include 

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();
    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;
}
3, sau đó là thực hiện một tập lệnh Python được mã hóa cứng in ngày và giờ. Sau đó, cuộc gọi
#define PY_SSIZE_T_CLEAN
#include 

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();
    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;
}
9 sẽ tắt trình thông dịch, sau đó là kết thúc chương trình. Trong một chương trình thực, bạn có thể muốn lấy tập lệnh Python từ một nguồn khác, có thể là thói quen biên tập văn bản, tệp hoặc cơ sở dữ liệu. Nhận mã python từ một tệp có thể được thực hiện tốt hơn bằng cách sử dụng hàm
#define PY_SSIZE_T_CLEAN
#include 

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();
    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;
}
5, giúp bạn tiết kiệm rắc rối trong việc phân bổ không gian bộ nhớ và tải nội dung tệp.

1.2. Ngoài việc nhúng mức rất cao: Tổng quanBeyond Very High Level Embedding: An overview¶

Giao diện cấp cao cung cấp cho bạn khả năng thực hiện các phần mã python tùy ý từ ứng dụng của bạn, nhưng việc trao đổi giá trị dữ liệu khá cồng kềnh khi nói ít nhất. Nếu bạn muốn điều đó, bạn nên sử dụng các cuộc gọi cấp thấp hơn. Với chi phí phải viết thêm mã C, bạn có thể đạt được hầu hết mọi thứ.

Cần lưu ý rằng việc mở rộng Python và nhúng Python là hoạt động khá giống nhau, mặc dù ý định khác nhau. Hầu hết các chủ đề được thảo luận trong các chương trước vẫn còn hợp lệ. Để hiển thị điều này, hãy xem xét mã mở rộng từ Python đến C thực sự làm gì:

  1. Chuyển đổi các giá trị dữ liệu từ Python sang C,

  2. Thực hiện lệnh gọi chức năng đến thói quen C bằng cách sử dụng các giá trị được chuyển đổi và

  3. Chuyển đổi các giá trị dữ liệu từ cuộc gọi từ C sang Python.

Khi nhúng python, mã giao diện không có:

  1. Chuyển đổi giá trị dữ liệu từ C sang Python,

  2. Thực hiện cuộc gọi chức năng đến thói quen giao diện Python bằng cách sử dụng các giá trị được chuyển đổi và

  3. Chuyển đổi các giá trị dữ liệu từ cuộc gọi từ Python sang C.

Như bạn có thể thấy, các bước chuyển đổi dữ liệu chỉ đơn giản là được hoán đổi để phù hợp với hướng khác nhau của chuyển giao ngôn ngữ. Sự khác biệt duy nhất là thói quen mà bạn gọi giữa cả hai chuyển đổi dữ liệu. Khi mở rộng, bạn gọi một thói quen C, khi nhúng, bạn gọi thói quen Python.

Chương này sẽ không thảo luận về cách chuyển đổi dữ liệu từ Python sang C và ngược lại. Ngoài ra, việc sử dụng đúng các tài liệu tham khảo và xử lý các lỗi được cho là được hiểu. Vì các khía cạnh này không khác nhau so với việc mở rộng trình thông dịch, bạn có thể tham khảo các chương trước để biết thông tin cần thiết.

1.3. Nhúng thuần túyPure Embedding¶

Chương trình đầu tiên nhằm mục đích thực thi một chức năng trong tập lệnh Python. Giống như trong phần về giao diện cấp độ rất cao, trình thông dịch Python không tương tác trực tiếp với ứng dụng (nhưng điều đó sẽ thay đổi trong phần tiếp theo).

Mã để chạy một hàm được xác định trong tập lệnh Python là:

#define PY_SSIZE_T_CLEAN
#include 

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();
    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;
}

Mã này tải một tập lệnh Python bằng cách sử dụng

def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c
1 và gọi hàm có tên trong
def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c
2. Các đối số số nguyên của nó là các giá trị khác của mảng
def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c
3. Nếu bạn biên dịch và liên kết chương trình này (hãy gọi cho cuộc gọi thực thi đã hoàn thành) và sử dụng nó để thực thi tập lệnh Python, chẳng hạn như:compile and link this program (let’s call the finished executable call), and use it to execute a Python script, such as:

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

Sau đó, kết quả nên là:

$ call multiply multiply 3 2
Will compute 3 times 2
Result of call: 6

Mặc dù chương trình này khá lớn cho chức năng của nó, nhưng hầu hết các mã là để chuyển đổi dữ liệu giữa Python và C và để báo cáo lỗi. Phần thú vị liên quan đến việc nhúng python bắt đầu với

Py_Initialize();
pName = PyUnicode_DecodeFSDefault(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);

Sau khi khởi tạo trình thông dịch, tập lệnh được tải bằng

def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c
4. Thói quen này cần một chuỗi python làm đối số của nó, được xây dựng bằng thói quen chuyển đổi dữ liệu
def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c
5.

pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */

if (pFunc && PyCallable_Check(pFunc)) {
    ...
}
Py_XDECREF(pFunc);

Khi tập lệnh được tải, tên mà chúng tôi đang tìm kiếm được truy xuất bằng cách sử dụng

def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c
6. Nếu tên tồn tại và đối tượng được trả về có thể gọi được, bạn có thể cho rằng đó là một hàm. Chương trình sau đó tiến hành bằng cách xây dựng một bộ lý đối số như bình thường. Cuộc gọi đến chức năng Python sau đó được thực hiện với:

pValue = PyObject_CallObject(pFunc, pArgs);

Khi trả về hàm,

def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c
7 là
def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c
8 hoặc nó chứa tham chiếu đến giá trị trả về của hàm. Hãy chắc chắn để phát hành tham chiếu sau khi kiểm tra giá trị.

1.4. Kéo dài Python¶ nhúngExtending Embedded Python¶

Cho đến bây giờ, trình thông dịch python nhúng không có quyền truy cập vào chức năng từ chính ứng dụng. API Python cho phép điều này bằng cách mở rộng trình thông dịch nhúng. Đó là, trình thông dịch được nhúng được mở rộng với các thói quen được cung cấp bởi ứng dụng. Mặc dù nghe có vẻ phức tạp, nó không quá tệ. Chỉ cần quên một thời gian rằng ứng dụng bắt đầu trình thông dịch Python. Thay vào đó, hãy coi ứng dụng này là một tập hợp các chương trình con và viết một số mã keo cho phép Python truy cập vào các thói quen đó, giống như bạn sẽ viết một phần mở rộng Python bình thường. Ví dụ:

static int numargs=0;

/* Return the number of arguments of the application command line */
static PyObject*
emb_numargs(PyObject *self, PyObject *args)
{
    if(!PyArg_ParseTuple(args, ":numargs"))
        return NULL;
    return PyLong_FromLong(numargs);
}

static PyMethodDef EmbMethods[] = {
    {"numargs", emb_numargs, METH_VARARGS,
     "Return the number of arguments received by the process."},
    {NULL, NULL, 0, NULL}
};

static PyModuleDef EmbModule = {
    PyModuleDef_HEAD_INIT, "emb", NULL, -1, EmbMethods,
    NULL, NULL, NULL, NULL
};

static PyObject*
PyInit_emb(void)
{
    return PyModule_Create(&EmbModule);
}

Chèn mã trên ngay trên hàm

def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c
9. Ngoài ra, chèn hai câu sau khi gọi đến
#define PY_SSIZE_T_CLEAN
#include 

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();
    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;
}
3:

numargs = argc;
PyImport_AppendInittab("emb", &PyInit_emb);

Hai dòng này khởi tạo biến

$ call multiply multiply 3 2
Will compute 3 times 2
Result of call: 6
1 và làm cho hàm
$ call multiply multiply 3 2
Will compute 3 times 2
Result of call: 6
2 có thể truy cập được vào trình thông dịch Python nhúng. Với các phần mở rộng này, kịch bản Python có thể làm những việc như

import emb
print("Number of arguments", emb.numargs())

Trong một ứng dụng thực, các phương thức sẽ hiển thị API của ứng dụng cho Python.

1.5. Nhúng Python vào C ++ ¶Embedding Python in C++¶

Cũng có thể nhúng Python vào chương trình C ++; Chính xác cách thực hiện điều này sẽ phụ thuộc vào các chi tiết của hệ thống C ++ được sử dụng; Nói chung, bạn sẽ cần viết chương trình chính trong C ++ và sử dụng trình biên dịch C ++ để biên dịch và liên kết chương trình của bạn. Không cần phải biên dịch lại Python bằng cách sử dụng C ++.

1.6. Biên dịch và liên kết dưới các hệ thống giống như UnixCompiling and Linking under Unix-like systems¶

Không nhất thiết là tầm thường để tìm các cờ phù hợp để chuyển đến trình biên dịch (và trình liên kết) của bạn để nhúng trình thông dịch python vào ứng dụng của bạn, đặc biệt là vì Python cần tải các mô -đun thư viện được triển khai dưới dạng các phần mở rộng động (

$ call multiply multiply 3 2
Will compute 3 times 2
Result of call: 6
3) được liên kết với nó .

Để tìm hiểu các cờ biên dịch và trình liên kết cần thiết, bạn có thể thực thi tập lệnh

$ call multiply multiply 3 2
Will compute 3 times 2
Result of call: 6
4 được tạo như một phần của quy trình cài đặt (tập lệnh
$ call multiply multiply 3 2
Will compute 3 times 2
Result of call: 6
5 cũng có thể có sẵn). Kịch bản này có một số tùy chọn, trong đó các tùy chọn sau đây sẽ hữu ích trực tiếp cho bạn:

  • $ call multiply multiply 3 2
    Will compute 3 times 2
    Result of call: 6
    
    6 sẽ cung cấp cho bạn các cờ được đề xuất khi biên dịch:

    #define PY_SSIZE_T_CLEAN
    #include 
    
    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();
        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;
    }
    
    0

  • $ call multiply multiply 3 2
    Will compute 3 times 2
    Result of call: 6
    
    7 sẽ cung cấp cho bạn các cờ được đề xuất khi liên kết:

    #define PY_SSIZE_T_CLEAN
    #include 
    
    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();
        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;
    }
    
    1

Ghi chú

Để tránh sự nhầm lẫn giữa một số cài đặt Python (và đặc biệt là giữa Python hệ thống và Python được biên dịch của riêng bạn), bạn nên sử dụng đường dẫn tuyệt đối đến

$ call multiply multiply 3 2
Will compute 3 times 2
Result of call: 6
4, như trong ví dụ trên.

Nếu quy trình này không hiệu quả với bạn (nó không được đảm bảo hoạt động cho tất cả các nền tảng giống như Unix; tuy nhiên, chúng tôi hoan nghênh các báo cáo lỗi), bạn sẽ phải đọc tài liệu của hệ thống về liên kết động và/hoặc kiểm tra

$ call multiply multiply 3 2
Will compute 3 times 2
Result of call: 6
9 của Python (sử dụng
Py_Initialize();
pName = PyUnicode_DecodeFSDefault(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
0 để tìm vị trí của nó) và các tùy chọn biên dịch. Trong trường hợp này, mô -đun
Py_Initialize();
pName = PyUnicode_DecodeFSDefault(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
1 là một công cụ hữu ích để lấy chương trình các giá trị cấu hình mà bạn sẽ muốn kết hợp với nhau. Ví dụ:bug reports) you will have to read your system’s documentation about dynamic linking and/or examine Python’s
$ call multiply multiply 3 2
Will compute 3 times 2
Result of call: 6
9 (use
Py_Initialize();
pName = PyUnicode_DecodeFSDefault(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
0 to find its location) and compilation options. In this case, the
Py_Initialize();
pName = PyUnicode_DecodeFSDefault(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
1 module is a useful tool to programmatically extract the configuration values that you will want to combine together. For example:

#define PY_SSIZE_T_CLEAN
#include 

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();
    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;
}
2