Bảng html tương tác python

Các chương trước đã thảo luận về cách mở rộng Python, nghĩa là cách mở rộng chức năng của Python bằng cách đính kèm một thư viện các hàm C vào nó. Cũng có thể làm theo cách khác. làm phong phú thêm ứ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 triển khai một số chức năng của ứng dụng bằng Python thay vì C hoặc C++. Điều này có thể được sử dụng cho nhiều mục đích; . Bạn cũng có thể tự mình sử dụng 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à trình thông 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 trình thông dịch 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 mình. Một trong những việc 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. Có các cuộc gọi tùy chọn để chuyển đối số dòng lệnh cho 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 thông dịch viên. bạn có thể chuyển một chuỗi chứa các câu lệnh Python tới hoặc bạn có thể chuyển con trỏ tệp stdio và tên tệp (chỉ để nhận dạng trong thông báo lỗi) tới. Bạn cũng có thể gọi các thao tác 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

Các chi tiết về giao diện C của Python được đưa ra trong sách 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. Nhúng cấp độ rất cao

Hình thức nhúng Python đơn giản nhất là sử dụng giao diện cấp cao. Giao diện này nhằm thực thi tập lệnh Python mà không cần tương tác trực tiếp với ứng dụng. Ví dụ, điều này có thể được sử dụng để thực hiện một số thao tác 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 nên được gọi trước để thông báo cho trình thông dịch về đường dẫn đến 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 , tiếp theo là thực thi tập lệnh Python được mã hóa cứng để in ngày và giờ. Sau đó, cuộc gọi tắt trình thông dịch, tiếp theo 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 soạn thảo văn bản, tệp hoặc cơ sở dữ liệu. Lấy 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 chức năng này, giúp bạn tránh được sự cố cấp phát dung lượng bộ nhớ và tải nội dung tệp

1. 2. Hơn cả mức độ nhúng rất cao. Tổng quan

Giao diện cấp cao cung cấp cho bạn khả năng thực thi các đoạn mã Python tùy ý từ ứng dụng của bạn, nhưng việc trao đổi các giá trị dữ liệu khá cồng kềnh. 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 hoàn toàn giống nhau, mặc dù mục đích 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 hiệu lực. Để thấy điều này, hãy xem mã mở rộng từ Python sang C thực sự làm gì

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

  2. Thực hiện một lời gọi hàm đến một thói quen C bằng cách sử dụng các giá trị đã 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 sẽ

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

  2. Thực hiện một lệnh gọi hàm tới một thói quen giao diện Python bằng cách sử dụng các giá trị đã 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 được hoán đổi đơn giản để phù hợp với hướng chuyển đổi ngôn ngữ khác nhau. Sự khác biệt duy nhất là thói quen mà bạn gọi giữa cả hai lần chuyển đổi dữ liệu. Khi mở rộng, bạn gọi một quy trình C, khi nhúng, bạn gọi một quy trình 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 tài liệu tham khảo và xử lý lỗi được cho là đã được hiểu. Vì các khía cạnh này không khác 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úy

Chương trình đầu tiên nhằm mục đích thực thi một hàm trong tập lệnh Python. Giống như trong phần về giao diện cấp 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 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ố 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 sử dụng chương trình này (hãy gọi 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ư

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

thì kết quả phải là

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

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

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 cách sử dụng. Quy trình này cần một chuỗi Python làm đối số của nó, được xây dựng bằng quy trình chuyển đổi dữ liệu

________số 8_______

Sau khi tập lệnh được tải, tên chúng tôi đang tìm kiếm sẽ được truy xuất bằng cách sử dụng. 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 một cách an toàn. Sau đó, chương trình tiếp tục bằng cách xây dựng một bộ đối số như bình thường. Cuộc gọi đến hàm 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 hoặc 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 chứa tham chiếu đến giá trị trả về của hàm. Đảm bảo phát hành tham chiếu sau khi kiểm tra giá trị

1. 4. Mở rộng nhúng Python

Cho đến thời điểm hiện tại, trình thông dịch nhúng Python 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. Nghĩa là, trình thông dịch nhúng được mở rộng với các thủ tục do ứng dụng cung cấp. Mặc dù nghe có vẻ phức tạp nhưng nó không quá tệ. Chỉ cần tạm thời quên rằng ứng dụng khởi động trình thông dịch Python. Thay vào đó, hãy coi ứng dụng 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 chương trình đó, giống như bạn sẽ viết một tiện ích 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 đoạn mã trên ngay phía 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, hãy chèn hai câu lệnh sau trước lệnh gọi đến

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 bằng trình thông dịch Python được nhúng. Với các tiện ích mở rộng này, tập lệnh Python có thể thực hiện những việc như

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

Trong một ứng dụng thực tế, 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++

Cũng có thể nhúng Python vào chương trình C++; . Không cần phải tự biên dịch lại Python bằng C++

1. 6. Biên dịch và liên kết trong các hệ thống giống Unix

Việc tìm đúng cờ để 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 không nhất thiết là chuyện nhỏ, đặ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 phần mở rộng động C (tệp _______6_______3) được liên kết với nó

Để tìm ra cờ trình 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 quá trình cài đặt (cũng có thể có tập lệnh
$ call multiply multiply 3 2
Will compute 3 times 2
Result of call: 6
5). Tập lệnh này có một số tùy chọn, trong đó những tùy chọn sau 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 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 tới

$ 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 phù hợp với bạn (không đảm bảo nó sẽ hoạt động với tất cả các nền tảng giống Unix; tuy nhiên, chúng tôi hoan nghênh ) 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 để tìm . Trong trường hợp này, mô-đun là một công cụ hữu ích để lập trình trích xuất các giá trị cấu hình mà bạn muốn kết hợp với nhau. Ví dụ