Hướng dẫn can i call c function from python? - tôi có thể gọi hàm c từ python không?

Bạn có phải là nhà phát triển Python với thư viện C hoặc C ++ mà bạn muốn sử dụng từ Python? Nếu vậy, các ràng buộc Python cho phép bạn gọi các chức năng và chuyển dữ liệu từ Python sang C hoặc C ++, cho phép bạn tận dụng các điểm mạnh của cả hai ngôn ngữ. Trong suốt hướng dẫn này, bạn sẽ thấy tổng quan về một số công cụ bạn có thể sử dụng để tạo các ràng buộc Python.Python bindings allow you to call functions and pass data from Python to C or C++, letting you take advantage of the strengths of both languages. Throughout this tutorial, you’ll see an overview of some of the tools you can use to create Python bindings.

Show

Trong hướng dẫn này, bạn sẽ tìm hiểu về:

  • Tại sao bạn muốn gọi C hoặc C ++ từ Pythoncall C or C++ from Python
  • Cách truyền dữ liệu giữa C và Pythonpass data between C and Python
  • Những công cụ và phương pháp nào có thể giúp bạn tạo ràng buộc Pythontools and methods can help you create Python bindings

Hướng dẫn này nhằm vào các nhà phát triển Python trung gian. Nó giả định kiến ​​thức cơ bản về Python và một số hiểu biết về các chức năng và loại dữ liệu trong C hoặc C ++. Bạn có thể nhận được tất cả các mã ví dụ mà bạn sẽ thấy trong hướng dẫn này bằng cách nhấp vào liên kết bên dưới:

Hãy cùng đi sâu vào việc nhìn vào các ràng buộc Python!

Tổng quan về ràng buộc Python

Trước khi bạn đi sâu vào cách gọi C từ Python, thật tốt khi dành thời gian cho lý do tại sao. Có một số tình huống tạo ra các ràng buộc Python để gọi thư viện C là một ý tưởng tuyệt vời:

  1. Bạn đã có một thư viện lớn, được thử nghiệm, ổn định được viết bằng C ++ mà bạn muốn tận dụng trong Python. Đây có thể là một thư viện truyền thông hoặc thư viện để nói chuyện với một phần cứng cụ thể. Những gì nó làm là không quan trọng. that you’d like to take advantage of in Python. This may be a communication library or a library to talk to a specific piece of hardware. What it does is unimportant.

  2. Bạn muốn tăng tốc một phần cụ thể trong mã Python của mình bằng cách chuyển đổi một phần quan trọng thành C. C không chỉ có tốc độ thực thi nhanh hơn mà còn cho phép bạn thoát khỏi các hạn chế của GIL, miễn là bạn cẩn thận. by converting a critical section to C. Not only does C have faster execution speed, but it also allows you to break free from the limitations of the GIL, provided you’re careful.

  3. Bạn muốn sử dụng các công cụ thử nghiệm Python để thực hiện thử nghiệm quy mô lớn các hệ thống của họ. to do large-scale testing of their systems.

Tất cả những điều trên là những lý do tuyệt vời để học cách tạo các ràng buộc Python để giao diện với thư viện C của bạn.

Bắt đầu nào!

Các loại dữ liệu Marshalling

Chờ đợi! Trước khi bạn bắt đầu viết các ràng buộc Python, hãy xem dữ liệu của Python và C Store và loại vấn đề này sẽ gây ra như thế nào. Đầu tiên, hãy để xác định Marshalling. Khái niệm này được định nghĩa bởi Wikipedia như sau:marshalling. This concept is defined by Wikipedia as follows:

Quá trình chuyển đổi biểu diễn bộ nhớ của một đối tượng thành định dạng dữ liệu phù hợp để lưu trữ hoặc truyền. (Nguồn)

Đối với mục đích của bạn, Marshalling là những gì các ràng buộc Python đang làm khi họ chuẩn bị dữ liệu để chuyển nó từ Python sang C hoặc ngược lại. Các ràng buộc Python cần phải thực hiện Marshalling vì Python và C lưu trữ dữ liệu theo những cách khác nhau. C lưu trữ dữ liệu ở dạng nhỏ gọn nhất trong bộ nhớ có thể. Nếu bạn sử dụng

$ invoke --list
Available tasks:

  all              Build and run all tests
  build-cffi       Build the CFFI Python bindings
  build-cmult      Build the shared library for the sample C code
  build-cppmult    Build the shared library for the sample C++ code
  build-cython     Build the cython extension module
  build-pybind11   Build the pybind11 wrapper library
  clean            Remove any built objects
  test-cffi        Run the script to test CFFI
  test-ctypes      Run the script to test ctypes
  test-cython      Run the script to test Cython
  test-pybind11    Run the script to test PyBind11
6, thì nó sẽ chỉ sử dụng tổng số 8 bit của bộ nhớ.

Trong Python, mặt khác, mọi thứ đều là một đối tượng. Điều này có nghĩa là mỗi số nguyên sử dụng một số byte trong bộ nhớ. Có bao nhiêu người sẽ phụ thuộc vào phiên bản Python mà bạn đang chạy, hệ điều hành của bạn và các yếu tố khác. Điều này có nghĩa là các ràng buộc python của bạn sẽ cần chuyển đổi số nguyên C thành số nguyên python cho mỗi số nguyên được truyền qua ranh giới.object. This means that each integer uses several bytes in memory. How many will depend on which version of Python you’re running, your operating system, and other factors. This means that your Python bindings will need to convert a C integer to a Python integer for each integer passed across the boundary.

Các loại dữ liệu khác có mối quan hệ tương tự giữa hai ngôn ngữ. Hãy lần lượt nhìn vào từng người:

  • Số nguyên lưu trữ số lượng đếm. Python lưu trữ các số nguyên với độ chính xác tùy ý, có nghĩa là bạn có thể lưu trữ rất, rất, số lượng lớn. C Chỉ định kích thước chính xác của số nguyên. Bạn cần nhận thức được các kích thước dữ liệu khi bạn di chuyển giữa các ngôn ngữ để ngăn các giá trị số nguyên Python tràn các biến số nguyên C. store counting numbers. Python stores integers with arbitrary precision, meaning that you can store very, very, large numbers. C specifies the exact sizes of integers. You need to be aware of data sizes when you’re moving between languages to prevent Python integer values from overflowing C integer variables.

  • Số điểm nổi là những con số có vị trí thập phân. Python có thể lưu trữ các số điểm nổi lớn hơn (và nhỏ hơn nhiều) hơn nhiều so với C. Điều này có nghĩa là bạn cũng sẽ phải chú ý đến các giá trị đó để đảm bảo chúng ở trong phạm vi. are numbers with a decimal place. Python can store much larger (and much smaller) floating-point numbers than C. This means that you’ll also have to pay attention to those values to ensure they stay in range.

  • Các số phức là những con số có một phần tưởng tượng. Trong khi Python có các số phức tạp tích hợp và C có số lượng phức tạp, nhưng không có phương pháp tích hợp nào để sắp xếp giữa chúng. Đối với các số phức tạp, bạn sẽ cần xây dựng một

    $ invoke --list
    Available tasks:
    
      all              Build and run all tests
      build-cffi       Build the CFFI Python bindings
      build-cmult      Build the shared library for the sample C code
      build-cppmult    Build the shared library for the sample C++ code
      build-cython     Build the cython extension module
      build-pybind11   Build the pybind11 wrapper library
      clean            Remove any built objects
      test-cffi        Run the script to test CFFI
      test-ctypes      Run the script to test ctypes
      test-cython      Run the script to test Cython
      test-pybind11    Run the script to test PyBind11
    
    7 hoặc
    $ invoke --list
    Available tasks:
    
      all              Build and run all tests
      build-cffi       Build the CFFI Python bindings
      build-cmult      Build the shared library for the sample C code
      build-cppmult    Build the shared library for the sample C++ code
      build-cython     Build the cython extension module
      build-pybind11   Build the pybind11 wrapper library
      clean            Remove any built objects
      test-cffi        Run the script to test CFFI
      test-ctypes      Run the script to test ctypes
      test-cython      Run the script to test Cython
      test-pybind11    Run the script to test PyBind11
    
    8 trong mã C để quản lý chúng.
    are numbers with an imaginary part. While Python has built-in complex numbers, and C has complex numbers, there’s no built-in method for marshalling between them. To marshal complex numbers, you’ll need to build a
    $ invoke --list
    Available tasks:
    
      all              Build and run all tests
      build-cffi       Build the CFFI Python bindings
      build-cmult      Build the shared library for the sample C code
      build-cppmult    Build the shared library for the sample C++ code
      build-cython     Build the cython extension module
      build-pybind11   Build the pybind11 wrapper library
      clean            Remove any built objects
      test-cffi        Run the script to test CFFI
      test-ctypes      Run the script to test ctypes
      test-cython      Run the script to test Cython
      test-pybind11    Run the script to test PyBind11
    
    7 or
    $ invoke --list
    Available tasks:
    
      all              Build and run all tests
      build-cffi       Build the CFFI Python bindings
      build-cmult      Build the shared library for the sample C code
      build-cppmult    Build the shared library for the sample C++ code
      build-cython     Build the cython extension module
      build-pybind11   Build the pybind11 wrapper library
      clean            Remove any built objects
      test-cffi        Run the script to test CFFI
      test-ctypes      Run the script to test ctypes
      test-cython      Run the script to test Cython
      test-pybind11    Run the script to test PyBind11
    
    8 in the C code to manage them.

  • Chuỗi là chuỗi các ký tự. Vì là một loại dữ liệu phổ biến như vậy, các chuỗi sẽ chứng minh là khá khó khăn khi bạn tạo ra các ràng buộc Python. Cũng như các loại dữ liệu khác, chuỗi cửa hàng Python và C ở các định dạng khá khác nhau. (Không giống như các loại dữ liệu khác, đây là một khu vực mà C và C ++ cũng khác nhau, điều này làm tăng thêm niềm vui!) are sequences of characters. For being such a common data type, strings will prove to be rather tricky when you’re creating Python bindings. As with other data types, Python and C store strings in quite different formats. (Unlike the other data types, this is an area where C and C++ differ as well, which adds to the fun!) Each of the solutions you’ll examine have slightly different methods for dealing with strings.

  • Các biến Boolean chỉ có thể có hai giá trị. Vì họ được hỗ trợ trong C, việc sắp xếp họ sẽ chứng minh là khá đơn giản. can have only two values. Since they’re supported in C, marshalling them will prove to be fairly straightforward.

Bên cạnh chuyển đổi kiểu dữ liệu, có những vấn đề khác mà bạn sẽ cần suy nghĩ khi bạn xây dựng các ràng buộc Python của mình. Hãy để tiếp tục khám phá chúng.

Hiểu các giá trị có thể thay đổi và bất biến

Ngoài tất cả các loại dữ liệu này, bạn cũng phải nhận thức được làm thế nào các đối tượng Python có thể bị thay đổi hoặc bất biến. C có một khái niệm tương tự với các tham số chức năng khi nói về từng giá trị hoặc vượt qua. Trong C, tất cả các tham số đều có giá trị. Nếu bạn muốn cho phép một hàm thay đổi một biến trong người gọi, thì bạn cần chuyển một con trỏ đến biến đó.mutable or immutable. C has a similar concept with function parameters when talking about pass-by-value or pass-by-reference. In C, all parameters are pass-by-value. If you want to allow a function to change a variable in the caller, then you need to pass a pointer to that variable.

Bạn có thể tự hỏi nếu bạn có thể vượt qua giới hạn bất biến bằng cách chuyển một đối tượng bất biến cho C bằng cách sử dụng một con trỏ. Trừ khi bạn đi đến các thái cực xấu xí và không thể thực hiện được, Python đã giành được một con trỏ cho một đối tượng, vì vậy điều này không hoạt động. Nếu bạn muốn sửa đổi một đối tượng Python trong C, thì bạn sẽ cần thực hiện các bước bổ sung để đạt được điều này. Các bước này sẽ phụ thuộc vào công cụ bạn sử dụng, như bạn sẽ thấy bên dưới.immutable restriction by simply passing an immutable object to C using a pointer. Unless you go to ugly and non-portable extremes, Python won’t give you a pointer to an object, so this just doesn’t work. If you want to modify a Python object in C, then you’ll need to take extra steps to achieve this. These steps will be dependent on which tools you use, as you’ll see below.

Vì vậy, bạn có thể thêm tính bất biến vào danh sách kiểm tra các mục của mình để xem xét khi bạn tạo các ràng buộc Python. Điểm dừng chân cuối cùng của bạn trong chuyến lưu diễn lớn về việc tạo danh sách kiểm tra này là làm thế nào để xử lý các cách khác nhau mà Python và C đối phó với quản lý bộ nhớ.

Quản lý bộ nhớ

C và Python quản lý bộ nhớ khác nhau. Trong C, nhà phát triển phải quản lý tất cả các phân bổ bộ nhớ và đảm bảo chúng được giải phóng một lần và chỉ một lần. Python chăm sóc điều này cho bạn bằng cách sử dụng một người thu gom rác.manage memory differently. In C, the developer must manage all memory allocations and ensure they’re freed once and only once. Python takes care of this for you using a garbage collector.

Mặc dù mỗi phương pháp này đều có lợi thế của nó, nhưng nó có thêm một nếp nhăn vào việc tạo ra các ràng buộc Python. Bạn cần phải nhận thức được nơi bộ nhớ cho mỗi đối tượng được phân bổ và đảm bảo rằng nó chỉ được giải phóng ở cùng một phía của rào cản ngôn ngữ.where the memory for each object was allocated and ensure that it’s only freed on the same side of the language barrier.

Ví dụ: một đối tượng Python được tạo khi bạn đặt

$ invoke --list
Available tasks:

  all              Build and run all tests
  build-cffi       Build the CFFI Python bindings
  build-cmult      Build the shared library for the sample C code
  build-cppmult    Build the shared library for the sample C++ code
  build-cython     Build the cython extension module
  build-pybind11   Build the pybind11 wrapper library
  clean            Remove any built objects
  test-cffi        Run the script to test CFFI
  test-ctypes      Run the script to test ctypes
  test-cython      Run the script to test Cython
  test-pybind11    Run the script to test PyBind11
9. Bộ nhớ cho điều này được phân bổ ở phía Python và cần được thu thập rác. May mắn thay, với các đối tượng Python, nó khá khó để làm bất cứ điều gì khác. Hãy xem Converse trong C, nơi bạn trực tiếp phân bổ một khối bộ nhớ:

int* iPtr = (int*)malloc(sizeof(int));

Khi bạn làm điều này, bạn cần đảm bảo rằng con trỏ này được giải phóng trong C. Điều này có thể có nghĩa là thêm mã vào các ràng buộc Python của bạn để làm điều này.

Điều đó làm tròn danh sách kiểm tra của bạn về các chủ đề chung. Hãy để bắt đầu thiết lập hệ thống của bạn để bạn có thể viết một số mã!

Thiết lập môi trường của bạn

Đối với hướng dẫn này, bạn sẽ sử dụng các thư viện C và C ++ từ trước từ repo Python GitHub thực sự để hiển thị một thử nghiệm của từng công cụ. Mục đích là bạn sẽ có thể sử dụng những ý tưởng này cho bất kỳ thư viện C nào. Để làm theo cùng với tất cả các ví dụ ở đây, bạn sẽ cần phải có những điều sau:

  • Thư viện C ++ được cài đặt và kiến ​​thức về đường dẫn để gọi dòng lệnhC++ library installed and knowledge of the path for command-line invocation
  • Công cụ phát triển Python:development tools:
    • Đối với Linux, đây là gói
      // cmult.c
      float cmult(int int_param, float float_param) {
          float return_value = int_param * float_param;
          printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
                  float_param, return_value);
          return return_value;
      }
      
      0 hoặc
      // cmult.c
      float cmult(int int_param, float float_param) {
          float return_value = int_param * float_param;
          printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
                  float_param, return_value);
          return return_value;
      }
      
      1, tùy thuộc vào phân phối của bạn.
    • Đối với Windows, có nhiều tùy chọn.
  • Python 3.6 trở lên or greater
  • Một môi trường ảo (được đề xuất, nhưng không bắt buộc)virtual environment (recommended, but not required)
  • Công cụ
    // cmult.c
    float cmult(int int_param, float float_param) {
        float return_value = int_param * float_param;
        printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
                float_param, return_value);
        return return_value;
    }
    
    2
    // cmult.c
    float cmult(int int_param, float float_param) {
        float return_value = int_param * float_param;
        printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
                float_param, return_value);
        return return_value;
    }
    
    2
    tool

Cái cuối cùng có thể là mới đối với bạn, vì vậy, hãy để xem xét kỹ hơn về nó.

Sử dụng công cụ // cmult.c float cmult(int int_param, float float_param) { float return_value = int_param * float_param; printf(" In cmult : int: %d float %.1f returning %.1f\n", int_param, float_param, return_value); return return_value; } 2

// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2 là công cụ bạn sẽ sử dụng để xây dựng và kiểm tra các ràng buộc Python của bạn trong hướng dẫn này. Nó có mục đích tương tự như
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
5 nhưng sử dụng Python thay vì Makefiles. Bạn cần phải cài đặt
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2 trong môi trường ảo của mình bằng cách sử dụng
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
7:

$ python3 -m pip install invoke

Để chạy nó, bạn nhập

// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2 theo sau là nhiệm vụ bạn muốn thực thi:

$ invoke build-cmult
==================================================
= Building C Library
* Complete

Để xem các nhiệm vụ nào có sẵn, bạn sử dụng tùy chọn

// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
9:

$ invoke --list
Available tasks:

  all              Build and run all tests
  build-cffi       Build the CFFI Python bindings
  build-cmult      Build the shared library for the sample C code
  build-cppmult    Build the shared library for the sample C++ code
  build-cython     Build the cython extension module
  build-pybind11   Build the pybind11 wrapper library
  clean            Remove any built objects
  test-cffi        Run the script to test CFFI
  test-ctypes      Run the script to test ctypes
  test-cython      Run the script to test Cython
  test-pybind11    Run the script to test PyBind11

Lưu ý rằng khi bạn nhìn vào tệp

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
0 nơi các tác vụ
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2 được xác định, bạn sẽ thấy tên của tác vụ thứ hai được liệt kê là
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
2. Tuy nhiên, đầu ra từ
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
9 cho thấy nó là
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
4. Dấu trừ (
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
5) có thể được sử dụng như một phần của tên Python, do đó, tệp sử dụng dấu gạch dưới (
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
6) thay thế.

Đối với mỗi công cụ bạn sẽ kiểm tra, sẽ có một tác vụ

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
7 và
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
8 được xác định. Ví dụ: để chạy mã cho
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, bạn có thể nhập
// cmult.h
float cmult(int int_param, float float_param);
0. Một ngoại lệ là
// cmult.h
float cmult(int int_param, float float_param);
1, vì không có giai đoạn xây dựng cho
// cmult.h
float cmult(int int_param, float float_param);
1. Ngoài ra, có hai nhiệm vụ đặc biệt được thêm vào để thuận tiện:

  • // cmult.h
    float cmult(int int_param, float float_param);
    
    3 chạy các tác vụ xây dựng và kiểm tra cho tất cả các công cụ.
    runs the build and test tasks for all tools.
  • // cmult.h
    float cmult(int int_param, float float_param);
    
    4 xóa bất kỳ tệp được tạo.
    removes any generated files.

Bây giờ, bạn đã có cảm giác về cách chạy mã, hãy để xem qua mã C mà bạn sẽ gói trước khi nhấn tổng quan về công cụ.

Nguồn C hoặc C ++

Trong mỗi phần ví dụ bên dưới, bạn sẽ tạo các ràng buộc Python cho cùng một chức năng trong C hoặc C ++. Các phần này nhằm cung cấp cho bạn một hương vị của mỗi phương pháp trông như thế nào, thay vì hướng dẫn chuyên sâu về công cụ đó, vì vậy chức năng mà bạn sẽ bọc là nhỏ. Chức năng mà bạn sẽ tạo các ràng buộc Python để lấy

// cmult.h
float cmult(int int_param, float float_param);
5 và
// cmult.h
float cmult(int int_param, float float_param);
6 làm tham số đầu vào và trả về
// cmult.h
float cmult(int int_param, float float_param);
6 mà sản phẩm của hai số:creating Python bindings for the same function in either C or C++. These sections are intended to give you a taste of what each method looks like, rather than an in-depth tutorial on that tool, so the function you’ll wrap is small. The function you’ll create Python bindings for takes an
// cmult.h
float cmult(int int_param, float float_param);
5 and a
// cmult.h
float cmult(int int_param, float float_param);
6 as input parameters and returns a
// cmult.h
float cmult(int int_param, float float_param);
6 that’s the product of the two numbers:

// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}

Các hàm C và C ++ gần như giống hệt nhau, với sự khác biệt nhỏ và chuỗi giữa chúng. Bạn có thể nhận được một bản sao của tất cả các mã bằng cách nhấp vào liên kết bên dưới:

Bây giờ bạn đã được sao chép repo và các công cụ của bạn được cài đặt, bạn có thể xây dựng và kiểm tra các công cụ. Vì vậy, hãy để Lặn đi vào từng phần dưới đây!

// cmult.h float cmult(int int_param, float float_param); 1

Bạn sẽ bắt đầu với

// cmult.h
float cmult(int int_param, float float_param);
1, đây là một công cụ trong thư viện tiêu chuẩn để tạo các ràng buộc Python. Nó cung cấp một bộ công cụ cấp thấp để tải các thư viện được chia sẻ và dữ liệu sắp xếp giữa Python và C.

Cách nó cài đặt

Một trong những lợi thế lớn của

// cmult.h
float cmult(int int_param, float float_param);
1 là nó là một phần của thư viện tiêu chuẩn Python. Nó đã được thêm vào Python phiên bản 2.5, vì vậy nó rất có thể bạn đã có nó. Bạn có thể
x, y = 6, 2.3
answer = c_lib.cmult(x, y)
1 nó giống như bạn làm với các mô -đun
x, y = 6, 2.3
answer = c_lib.cmult(x, y)
2 hoặc
x, y = 6, 2.3
answer = c_lib.cmult(x, y)
3.

Gọi chức năng

Tất cả các mã để tải thư viện C của bạn và gọi chức năng sẽ nằm trong chương trình Python của bạn. Điều này là tuyệt vời vì không có bước bổ sung trong quá trình của bạn. Bạn chỉ cần chạy chương trình của bạn, và mọi thứ được chăm sóc. Để tạo các ràng buộc Python của bạn trong

// cmult.h
float cmult(int int_param, float float_param);
1, bạn cần thực hiện các bước sau:

  1. Tải thư viện của bạn. your library.
  2. Bao bọc một số tham số đầu vào của bạn. some of your input parameters.
  3. Nói với
    // cmult.h
    float cmult(int int_param, float float_param);
    
    1 Loại trả về chức năng của bạn.
    // cmult.h
    float cmult(int int_param, float float_param);
    
    1 the return type of your function.

Bạn lần lượt nhìn vào từng cái này.

Tải thư viện

// cmult.h
float cmult(int int_param, float float_param);
1 cung cấp một số cách để bạn tải thư viện dùng chung, một số trong đó là dành riêng cho nền tảng. Ví dụ của bạn, bạn sẽ tạo một đối tượng
x, y = 6, 2.3
answer = c_lib.cmult(x, y)
7 trực tiếp bằng cách chuyển qua đường dẫn đầy đủ đến thư viện được chia sẻ mà bạn muốn:

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)

Điều này sẽ hoạt động cho các trường hợp khi thư viện chia sẻ có cùng thư mục với tập lệnh Python của bạn, nhưng hãy cẩn thận khi bạn cố gắng tải các thư viện từ các gói khác ngoài các ràng buộc Python của bạn. Có nhiều chi tiết để tải thư viện và tìm đường dẫn trong tài liệu

// cmult.h
float cmult(int int_param, float float_param);
1 là nền tảng và tình huống cụ thể.

Bây giờ bạn có thư viện được tải vào Python, bạn có thể thử gọi nó!

Gọi chức năng của bạn

Hãy nhớ rằng nguyên mẫu chức năng cho hàm C của bạn như sau:

// cmult.h
float cmult(int int_param, float float_param);

Bạn cần phải vượt qua một số nguyên và một chiếc phao và có thể mong đợi để có được một chiếc phao được trả về. Số nguyên và phao có sự hỗ trợ bản địa ở cả Python và trong C, vì vậy bạn mong đợi trường hợp này sẽ hoạt động cho các giá trị hợp lý.

Khi bạn đã tải thư viện vào các ràng buộc Python của mình, hàm sẽ là một thuộc tính của

x, y = 6, 2.3
answer = c_lib.cmult(x, y)
9, đó là đối tượng
$ invoke test-ctypes
Traceback (most recent call last):
  File "ctypes_test.py", line 16, in <module>
    answer = c_lib.cmult(x, y)
ctypes.ArgumentError: argument 2: <class 'TypeError'>: Don't know how to convert parameter 2
0 bạn đã tạo trước đó. Bạn có thể cố gắng gọi nó giống như thế này:

x, y = 6, 2.3
answer = c_lib.cmult(x, y)

Ối! Điều này không làm việc. Dòng này được nhận xét trong ví dụ repo vì nó thất bại. Nếu bạn cố gắng chạy với cuộc gọi đó, thì Python sẽ phàn nàn với một lỗi:

$ invoke test-ctypes
Traceback (most recent call last):
  File "ctypes_test.py", line 16, in <module>
    answer = c_lib.cmult(x, y)
ctypes.ArgumentError: argument 2: <class 'TypeError'>: Don't know how to convert parameter 2

Có vẻ như bạn cần phải nói

// cmult.h
float cmult(int int_param, float float_param);
1 về bất kỳ tham số nào phát sinh số nguyên.
// cmult.h
float cmult(int int_param, float float_param);
1 không có bất kỳ kiến ​​thức nào về chức năng trừ khi bạn nói rõ ràng. Bất kỳ tham số nào mà không được đánh dấu khác được coi là một số nguyên.
// cmult.h
float cmult(int int_param, float float_param);
1 không biết cách chuyển đổi giá trị
$ invoke test-ctypes
Traceback (most recent call last):
  File "ctypes_test.py", line 16, in <module>
    answer = c_lib.cmult(x, y)
ctypes.ArgumentError: argument 2: <class 'TypeError'>: Don't know how to convert parameter 2
4 mà Lôi lưu trữ trong
$ invoke test-ctypes
Traceback (most recent call last):
  File "ctypes_test.py", line 16, in <module>
    answer = c_lib.cmult(x, y)
ctypes.ArgumentError: argument 2: <class 'TypeError'>: Don't know how to convert parameter 2
5 thành một số nguyên, vì vậy nó không thành công.

Để khắc phục điều này, bạn sẽ cần phải tạo

$ invoke test-ctypes
Traceback (most recent call last):
  File "ctypes_test.py", line 16, in <module>
    answer = c_lib.cmult(x, y)
ctypes.ArgumentError: argument 2: <class 'TypeError'>: Don't know how to convert parameter 2
6 từ số. Bạn có thể làm điều đó trong dòng mà bạn gọi là chức năng:

# ctypes_test.py
answer = c_lib.cmult(x, ctypes.c_float(y))
print(f"    In Python: int: {x} float {y:.1f} return val {answer:.1f}")

Bây giờ, khi bạn chạy mã này, nó sẽ trả về sản phẩm của hai số bạn đã vượt qua:

$ python3 -m pip install invoke
0

Đợi một chút

$ invoke test-ctypes
Traceback (most recent call last):
  File "ctypes_test.py", line 16, in <module>
    answer = c_lib.cmult(x, y)
ctypes.ArgumentError: argument 2: <class 'TypeError'>: Don't know how to convert parameter 2
7 nhân với
$ invoke test-ctypes
Traceback (most recent call last):
  File "ctypes_test.py", line 16, in <module>
    answer = c_lib.cmult(x, y)
ctypes.ArgumentError: argument 2: <class 'TypeError'>: Don't know how to convert parameter 2
4 không phải là
$ invoke test-ctypes
Traceback (most recent call last):
  File "ctypes_test.py", line 16, in <module>
    answer = c_lib.cmult(x, y)
ctypes.ArgumentError: argument 2: <class 'TypeError'>: Don't know how to convert parameter 2
9!

Nó chỉ ra rằng, giống như các tham số đầu vào,

// cmult.h
float cmult(int int_param, float float_param);
1 giả định chức năng của bạn trả về một
// cmult.h
float cmult(int int_param, float float_param);
5. Trong thực tế, chức năng của bạn trả về một
// cmult.h
float cmult(int int_param, float float_param);
6, đang bị Marshalled không chính xác. Giống như tham số đầu vào, bạn cần nói
// cmult.h
float cmult(int int_param, float float_param);
1 để sử dụng một loại khác. Cú pháp ở đây hơi khác nhau:assumes your function returns an
// cmult.h
float cmult(int int_param, float float_param);
5. In actuality, your function returns a
// cmult.h
float cmult(int int_param, float float_param);
6, which is getting marshalled incorrectly. Just like the input parameter, you need to tell
// cmult.h
float cmult(int int_param, float float_param);
1 to use a different type. The syntax here is slightly different:

$ python3 -m pip install invoke
1

Điều đó sẽ làm các trick. Hãy cùng chạy toàn bộ mục tiêu

# ctypes_test.py
answer = c_lib.cmult(x, ctypes.c_float(y))
print(f"    In Python: int: {x} float {y:.1f} return val {answer:.1f}")
4 và xem những gì bạn đã có. Hãy nhớ rằng, phần đầu ra đầu tiên là trước khi bạn sửa
# ctypes_test.py
answer = c_lib.cmult(x, ctypes.c_float(y))
print(f"    In Python: int: {x} float {y:.1f} return val {answer:.1f}")
5 của chức năng là một chiếc phao:before you fixed the
# ctypes_test.py
answer = c_lib.cmult(x, ctypes.c_float(y))
print(f"    In Python: int: {x} float {y:.1f} return val {answer:.1f}")
5 of the function to be a float:

$ python3 -m pip install invoke
2

Cái đó tốt hơn! Mặc dù phiên bản đầu tiên, chưa được xử lý đang trả về giá trị sai, phiên bản cố định của bạn đồng ý với hàm C. Cả C và Python đều nhận được kết quả tương tự! Bây giờ, nó hoạt động, hãy xem lý do tại sao bạn có thể hoặc không muốn sử dụng

// cmult.h
float cmult(int int_param, float float_param);
1.

Điểm mạnh và điểm yếu

Ưu điểm lớn nhất

// cmult.h
float cmult(int int_param, float float_param);
1 có so với các công cụ khác mà bạn sẽ kiểm tra ở đây là nó được tích hợp vào thư viện tiêu chuẩn. Nó cũng không yêu cầu thêm các bước, vì tất cả các công việc được thực hiện như một phần của chương trình Python của bạn.built into the standard library. It also requires no extra steps, as all of the work is done as part of your Python program.

Ngoài ra, các khái niệm được sử dụng là cấp thấp, điều này làm cho các bài tập như bài tập bạn vừa có thể quản lý được. Tuy nhiên, các nhiệm vụ phức tạp hơn phát triển cồng kềnh với việc thiếu tự động hóa. Trong phần tiếp theo, bạn sẽ thấy một công cụ bổ sung một số tự động hóa vào quy trình.

# ctypes_test.py import ctypes import pathlib if __name__ == "__main__": # Load the shared library into ctypes libname = pathlib.Path().absolute() / "libcmult.so" c_lib = ctypes.CDLL(libname) 9

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 là giao diện chức năng nước ngoài C cho Python. Nó có một cách tiếp cận tự động hơn để tạo ra các ràng buộc Python.
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 có nhiều cách mà bạn có thể xây dựng và sử dụng các ràng buộc Python của mình. Có hai tùy chọn khác nhau để chọn, cung cấp cho bạn bốn chế độ có thể:C Foreign Function Interface for Python. It takes a more automated approach to generate Python bindings.
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 has multiple ways in which you can build and use your Python bindings. There are two different options to select from, which gives you four possible modes:

  • API VS API: Chế độ API sử dụng trình biên dịch C để tạo mô -đun Python đầy đủ, trong khi chế độ ABI tải thư viện chung và tương tác trực tiếp với nó. Không cần chạy trình biên dịch, việc lấy các cấu trúc và tham số chính xác là dễ bị lỗi. Tài liệu khuyến nghị sử dụng chế độ API. API mode uses a C compiler to generate a full Python module, whereas ABI mode loads the shared library and interacts with it directly. Without running the compiler, getting the structures and parameters correct is error-prone. The documentation heavily recommends using the API mode.

  • nội tuyến so với ngoại tuyến: Sự khác biệt giữa hai chế độ này là sự đánh đổi giữa tốc độ và sự tiện lợi: The difference between these two modes is a trade-off between speed and convenience:

    • Chế độ nội tuyến biên dịch các liên kết Python mỗi khi tập lệnh của bạn chạy. Điều này là thuận tiện, vì bạn không cần một bước xây dựng thêm. Nó, tuy nhiên, làm chậm chương trình của bạn. compiles the Python bindings every time your script runs. This is convenient, as you don’t need an extra build step. It does, however, slow down your program.
    • Chế độ ngoại tuyến yêu cầu một bước bổ sung để tạo các ràng buộc Python một lần và sau đó sử dụng chúng mỗi khi chương trình được chạy. Điều này nhanh hơn nhiều, nhưng điều đó có thể không quan trọng đối với ứng dụng của bạn. requires an extra step to generate the Python bindings a single time and then uses them each time the program is run. This is much faster, but that may not matter for your application.

Trong ví dụ này, bạn sẽ sử dụng chế độ ngoại tuyến API, tạo ra mã nhanh nhất và nói chung, trông tương tự như các ràng buộc Python khác mà bạn sẽ tạo sau này trong hướng dẫn này.

Cách nó cài đặt

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 không phải là một phần của thư viện tiêu chuẩn, bạn sẽ cần cài đặt nó trên máy của mình. Nó khuyên bạn nên tạo ra một môi trường ảo cho việc này. May mắn thay,
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 cài đặt với
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
7:

$ python3 -m pip install invoke
3

Điều này sẽ cài đặt gói vào môi trường ảo của bạn. Nếu bạn đã cài đặt từ

$ python3 -m pip install invoke
04, thì điều này sẽ được chăm sóc. Bạn có thể xem
$ python3 -m pip install invoke
04 bằng cách truy cập repo tại liên kết bên dưới:

Bây giờ bạn đã cài đặt

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, đó là thời gian để đưa nó vào một vòng quay!

Gọi chức năng

Không giống như

// cmult.h
float cmult(int int_param, float float_param);
1, với
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, bạn đã tạo ra một mô -đun Python đầy đủ. Bạn có thể
x, y = 6, 2.3
answer = c_lib.cmult(x, y)
1 mô -đun như bất kỳ mô -đun nào khác trong thư viện tiêu chuẩn. Có một số công việc bổ sung mà bạn sẽ phải làm để xây dựng mô -đun Python của mình. Để sử dụng các ràng buộc python
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 của bạn, bạn sẽ cần thực hiện các bước sau:

  • Viết một số mã Python mô tả các ràng buộc. some Python code describing the bindings.
  • Chạy mã đó để tạo một mô -đun có thể tải. that code to generate a loadable module.
  • Sửa đổi mã gọi để nhập và sử dụng mô -đun mới được tạo của bạn. the calling code to import and use your newly created module.

Điều đó có vẻ như rất nhiều công việc, nhưng bạn sẽ đi qua từng bước này và xem cách thức hoạt động của nó.

Viết các ràng buộc

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 cung cấp các phương thức để đọc tệp tiêu đề C để thực hiện hầu hết các công việc khi tạo các ràng buộc Python. Trong tài liệu cho
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, mã để thực hiện việc này được đặt trong một tệp Python riêng biệt. Đối với ví dụ này, bạn sẽ đặt mã đó trực tiếp vào công cụ xây dựng
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2, sử dụng các tệp Python làm đầu vào. Để sử dụng
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, bạn bắt đầu bằng cách tạo đối tượng
$ python3 -m pip install invoke
15, cung cấp ba phương pháp bạn cần:C header file to do most of the work when generating Python bindings. In the documentation for
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, the code to do this is placed in a separate Python file. For this example, you’ll place that code directly into the build tool
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2, which uses Python files as input. To use
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, you start by creating a
$ python3 -m pip install invoke
15 object, which provides the three methods you need:

$ python3 -m pip install invoke
4

Khi bạn có FFI, bạn sẽ sử dụng

$ python3 -m pip install invoke
16 để tự động xử lý nội dung của tệp tiêu đề. Điều này tạo ra các chức năng trình bao bọc cho bạn dữ liệu đầm lầy từ Python:

$ python3 -m pip install invoke
5

Đọc và xử lý tệp tiêu đề là bước đầu tiên. Sau đó, bạn cần sử dụng

$ python3 -m pip install invoke
17 để mô tả tệp nguồn mà
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 sẽ tạo:

$ python3 -m pip install invoke
6

Ở đây, một sự cố của các tham số mà bạn đã vượt qua:

  • $ python3 -m pip install invoke
    
    19 là tên cơ sở cho tệp nguồn sẽ được tạo trên hệ thống tệp của bạn.
    # ctypes_test.py
    import ctypes
    import pathlib
    
    if __name__ == "__main__":
        # Load the shared library into ctypes
        libname = pathlib.Path().absolute() / "libcmult.so"
        c_lib = ctypes.CDLL(libname)
    
    9 sẽ tạo tệp
    $ python3 -m pip install invoke
    
    21, biên dịch nó thành tệp
    $ python3 -m pip install invoke
    
    22 và liên kết nó với tệp
    $ python3 -m pip install invoke
    
    23 hoặc
    $ python3 -m pip install invoke
    
    24.
    is the base name for the source file that will be created on your file system.
    # ctypes_test.py
    import ctypes
    import pathlib
    
    if __name__ == "__main__":
        # Load the shared library into ctypes
        libname = pathlib.Path().absolute() / "libcmult.so"
        c_lib = ctypes.CDLL(libname)
    
    9 will generate a
    $ python3 -m pip install invoke
    
    21 file, compile it to a
    $ python3 -m pip install invoke
    
    22 file, and link it to a
    $ python3 -m pip install invoke
    
    23 or
    $ python3 -m pip install invoke
    
    24 file.

  • $ python3 -m pip install invoke
    
    25 là mã nguồn C tùy chỉnh sẽ được bao gồm trong nguồn được tạo trước khi nó được biên dịch. Ở đây, bạn chỉ bao gồm tệp
    $ python3 -m pip install invoke
    
    26 mà bạn tạo ra các ràng buộc, nhưng điều này có thể được sử dụng cho một số tùy chỉnh thú vị.
    is the custom C source code that will be included in the generated source before it’s compiled. Here, you just include the
    $ python3 -m pip install invoke
    
    26 file for which you’re generating bindings, but this can be used for some interesting customizations.

  • $ python3 -m pip install invoke
    
    27 cho biết trình liên kết tên của thư viện C đã tồn tại trước của bạn. Đây là một danh sách, vì vậy bạn có thể chỉ định một số thư viện nếu được yêu cầu. tells the linker the name of your pre-existing C library. This is a list, so you can specify several libraries if required.

  • $ python3 -m pip install invoke
    
    28 là danh sách các thư mục cho biết trình liên kết nơi tìm kiếm danh sách các thư viện trên. is a list of directories that tells the linker where to look for the above list of libraries.

  • $ python3 -m pip install invoke
    
    29 là một tập hợp các tùy chọn tạo ra một đối tượng được chia sẻ, sẽ nhìn vào đường dẫn hiện tại (
    $ python3 -m pip install invoke
    
    30) cho các thư viện khác mà nó cần tải.
    is a set of options that generate a shared object, which will look in the current path (
    $ python3 -m pip install invoke
    
    30) for other libraries it needs to load.

Xây dựng các ràng buộc Python

Gọi

$ python3 -m pip install invoke
17 không xây dựng các ràng buộc Python. Nó chỉ thiết lập siêu dữ liệu để mô tả những gì sẽ được tạo ra. Để xây dựng các ràng buộc Python, bạn cần gọi
$ python3 -m pip install invoke
32:

Điều này kết thúc mọi thứ bằng cách tạo tệp

$ python3 -m pip install invoke
21, tệp
$ python3 -m pip install invoke
22 và thư viện được chia sẻ. Nhiệm vụ
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2 bạn vừa đi qua có thể được chạy trên dòng lệnh để xây dựng các ràng buộc Python:

$ python3 -m pip install invoke
7

Bạn có các ràng buộc python

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 của mình, vì vậy đã đến lúc chạy mã này!

Gọi chức năng của bạn

Sau tất cả các công việc bạn đã làm để định cấu hình và chạy trình biên dịch

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, sử dụng các ràng buộc Python được tạo trông giống như sử dụng bất kỳ mô -đun Python nào khác:

$ python3 -m pip install invoke
8

Bạn nhập mô -đun mới và sau đó bạn có thể gọi trực tiếp

$ python3 -m pip install invoke
38. Để kiểm tra nó, hãy sử dụng tác vụ
$ python3 -m pip install invoke
39:

$ python3 -m pip install invoke
9

Điều này chạy chương trình

$ python3 -m pip install invoke
40 của bạn, trong đó kiểm tra các ràng buộc Python mới mà bạn đã tạo với
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9. Điều đó hoàn thành phần về viết và sử dụng các ràng buộc python
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 của bạn.

Điểm mạnh và điểm yếu

Có vẻ như

// cmult.h
float cmult(int int_param, float float_param);
1 đòi hỏi ít công việc hơn ví dụ
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 mà bạn vừa thấy. Mặc dù điều này đúng với trường hợp sử dụng này,
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 quy mô cho các dự án lớn hơn nhiều so với
// cmult.h
float cmult(int int_param, float float_param);
1 do tự động hóa phần lớn chức năng gói.automation of much of the function wrapping.

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 cũng tạo ra trải nghiệm người dùng khá khác.
// cmult.h
float cmult(int int_param, float float_param);
1 cho phép bạn tải thư viện C đã tồn tại trực tiếp vào chương trình Python của bạn.
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, mặt khác, tạo ra một mô -đun Python mới có thể được tải như các mô -đun Python khác.

Hơn nữa, với phương pháp ngoài dòng-API mà bạn đã sử dụng ở trên, thời gian phạt để tạo các ràng buộc Python được thực hiện một lần khi bạn xây dựng nó và không xảy ra mỗi khi bạn chạy mã của mình. Đối với các chương trình nhỏ, đây có thể không phải là vấn đề lớn, nhưng

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 có quy mô tốt hơn cho các dự án lớn hơn theo cách này.out-of-line-API method you used above, the time penalty for creating the Python bindings is done once when you build it and doesn’t happen each time you run your code. For small programs, this might not be a big deal, but
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 scales better to larger projects in this way, as well.

Giống như

// cmult.h
float cmult(int int_param, float float_param);
1, sử dụng
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 chỉ cho phép bạn giao tiếp trực tiếp với các thư viện C. Các thư viện C ++ yêu cầu rất nhiều công việc để sử dụng. Trong phần tiếp theo, bạn sẽ thấy một công cụ ràng buộc Python tập trung vào C ++.

$ python3 -m pip install invoke 53

$ python3 -m pip install invoke
53 có một cách tiếp cận khá khác để tạo ra các ràng buộc Python. Ngoài việc chuyển trọng tâm từ C sang C ++, nó cũng sử dụng C ++ để chỉ định và xây dựng mô -đun, cho phép nó tận dụng các công cụ siêu hình trong C ++. Giống như
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, các ràng buộc Python được tạo từ
$ python3 -m pip install invoke
53 là một mô -đun Python đầy đủ có thể được nhập và sử dụng trực tiếp.uses C++ to specify and build the module, allowing it to take advantage of the metaprogramming tools in C++. Like
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, the Python bindings generated from
$ python3 -m pip install invoke
53 are a full Python module that can be imported and used directly.

$ python3 -m pip install invoke
53 được mô hình hóa sau thư viện
$ python3 -m pip install invoke
58 và có giao diện tương tự. Tuy nhiên, nó hạn chế việc sử dụng nó cho C ++ 11 trở lên, tuy nhiên, cho phép nó đơn giản hóa và tăng tốc mọi thứ so với Boost, hỗ trợ mọi thứ.

Cách nó cài đặt

Phần đầu tiên của tài liệu

$ python3 -m pip install invoke
53 hướng dẫn bạn cách tải xuống và xây dựng các trường hợp thử nghiệm cho
$ python3 -m pip install invoke
53. Mặc dù điều này dường như không được yêu cầu nghiêm ngặt, nhưng làm việc thông qua các bước này sẽ đảm bảo bạn đã được thiết lập các công cụ C ++ và Python thích hợp.

Bạn sẽ muốn cài đặt công cụ này vào môi trường ảo của mình:

$ invoke build-cmult
==================================================
= Building C Library
* Complete
0

$ python3 -m pip install invoke
53 là một thư viện hoàn toàn tiêu đề, tương tự như phần lớn sự tăng cường. Điều này cho phép
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
7 cài đặt nguồn C ++ thực tế cho thư viện trực tiếp vào môi trường ảo của bạn.

Gọi chức năng

Trước khi bạn lao vào, xin lưu ý rằng bạn sử dụng tệp nguồn C ++ khác,

$ python3 -m pip install invoke
63, thay vì tệp C bạn đã sử dụng cho các ví dụ trước. Hàm về cơ bản giống nhau trong cả hai ngôn ngữ.you’re using a different C++ source file,
$ python3 -m pip install invoke
63, instead of the C file you used for the previous examples. The function is essentially the same in both languages.

Viết các ràng buộc

Tương tự như

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, bạn cần tạo một số mã để nói với công cụ cách xây dựng các ràng buộc Python của bạn. Không giống như
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9, mã này sẽ ở C ++ thay vì Python. May mắn thay, có một lượng mã tối thiểu cần thiết:

$ invoke build-cmult
==================================================
= Building C Library
* Complete
1

Hãy cùng nhìn vào một mảnh này tại một thời điểm, vì

$ python3 -m pip install invoke
53 gói rất nhiều thông tin thành một vài dòng.

Hai dòng đầu tiên bao gồm tệp

$ python3 -m pip install invoke
67 và tệp tiêu đề cho thư viện C ++ của bạn,
$ python3 -m pip install invoke
68. Sau đó, bạn có macro
$ python3 -m pip install invoke
69. Điều này mở rộng thành một khối mã C ++ được mô tả tốt trong nguồn
$ python3 -m pip install invoke
53:

Macro này tạo ra điểm nhập sẽ được gọi khi trình thông dịch Python nhập mô -đun mở rộng. Tên mô -đun được đưa ra là đối số đầu tiên và nó không nên được trích dẫn. Đối số macro thứ hai xác định một biến của loại

$ python3 -m pip install invoke
71 có thể được sử dụng để khởi tạo mô -đun. (Nguồn)

Điều này có ý nghĩa gì với bạn là, trong ví dụ này, bạn đã tạo một mô -đun có tên

$ python3 -m pip install invoke
72 và phần còn lại của mã sẽ sử dụng
$ python3 -m pip install invoke
73 làm tên của đối tượng
$ python3 -m pip install invoke
71. Trên dòng tiếp theo, bên trong hàm C ++ mà bạn xác định, bạn tạo một DocString cho mô -đun. Mặc dù đây là tùy chọn, nhưng nó lại là một liên lạc tốt đẹp để làm cho mô -đun của bạn trở nên pythonic hơn.

Cuối cùng, bạn có cuộc gọi

$ python3 -m pip install invoke
75. Điều này sẽ xác định một chức năng mà xuất khẩu bởi các ràng buộc Python mới của bạn, có nghĩa là nó sẽ được nhìn thấy từ Python. Trong ví dụ này, bạn đã vượt qua ba tham số:

  • $ python3 -m pip install invoke
    
    76 là tên được xuất của hàm mà bạn sẽ sử dụng trong Python. Như ví dụ này cho thấy, nó không cần phải khớp với tên của hàm C ++.
    is the exported name of the function that you’ll use in Python. As this example shows, it doesn’t need to match the name of the C++ function.
  • $ python3 -m pip install invoke
    
    77 lấy địa chỉ của hàm sẽ được xuất.
    takes the address of the function to be exported.
  • $ python3 -m pip install invoke
    
    78 là một tài liệu tùy chọn cho chức năng.
    is an optional docstring for the function.

Bây giờ bạn có mã cho các ràng buộc Python, hãy xem cách bạn có thể xây dựng nó thành một mô -đun Python.

Xây dựng các ràng buộc Python

Công cụ bạn sử dụng để xây dựng các ràng buộc Python trong

$ python3 -m pip install invoke
53 là chính trình biên dịch C ++. Bạn có thể cần sửa đổi mặc định cho trình biên dịch và hệ điều hành của bạn.

Để bắt đầu, bạn phải xây dựng thư viện C ++ mà bạn đang tạo ra các ràng buộc. Ví dụ, nhỏ này, bạn có thể xây dựng thư viện

$ python3 -m pip install invoke
80 trực tiếp vào thư viện ràng buộc Python. Tuy nhiên, đối với hầu hết các ví dụ trong thế giới thực, bạn sẽ có một thư viện có sẵn mà bạn muốn bọc, vì vậy bạn sẽ xây dựng thư viện
$ python3 -m pip install invoke
80 riêng biệt. Bản dựng là một cuộc gọi tiêu chuẩn đến trình biên dịch để xây dựng một thư viện được chia sẻ:

$ invoke build-cmult
==================================================
= Building C Library
* Complete
2

Chạy này với

$ python3 -m pip install invoke
82 tạo ra
$ python3 -m pip install invoke
83:

$ invoke build-cmult
==================================================
= Building C Library
* Complete
3

Mặt khác, bản dựng cho các ràng buộc Python yêu cầu một số chi tiết đặc biệt:

$ invoke build-cmult
==================================================
= Building C Library
* Complete
4

Hãy cùng đi qua từng dòng này. Dòng 3 chứa các cờ biên dịch C ++ khá chuẩn cho biết một số chi tiết, bao gồm cả bạn muốn tất cả các cảnh báo bị bắt và coi là lỗi, mà bạn muốn có một thư viện được chia sẻ và bạn đã sử dụng C ++ 11.Line 3 contains fairly standard C++ compiler flags that indicate several details, including that you want all warnings caught and treated as errors, that you want a shared library, and that you’re using C++11.

Dòng 4 là bước đầu tiên của phép thuật. Nó gọi mô -đun

$ python3 -m pip install invoke
84 để tạo ra các đường dẫn
$ python3 -m pip install invoke
85 thích hợp cho
$ python3 -m pip install invoke
53. Bạn có thể chạy lệnh này trực tiếp trên bảng điều khiển để xem nó làm gì:
is the first step of the magic. It calls the
$ python3 -m pip install invoke
84 module to have it produce the proper
$ python3 -m pip install invoke
85 paths for
$ python3 -m pip install invoke
53. You can run this command directly on the console to see what it does:

$ invoke build-cmult
==================================================
= Building C Library
* Complete
5

Đầu ra của bạn phải tương tự nhưng hiển thị các đường dẫn khác nhau.

Trong dòng 5 của cuộc gọi biên dịch của bạn, bạn có thể thấy rằng bạn cũng sẽ thêm đường dẫn vào Python Dev

$ python3 -m pip install invoke
87. Mặc dù nó khuyến nghị rằng bạn không liên kết với thư viện Python, nguồn này cần một số mã từ
$ python3 -m pip install invoke
88 để thực hiện phép thuật của nó. May mắn thay, mã nó sử dụng khá ổn định trên các phiên bản Python.line 5 of your compilation call, you can see that you’re also adding the path to the Python dev
$ python3 -m pip install invoke
87. While it’s recommended that you don’t link against the Python library itself, the source needs some code from
$ python3 -m pip install invoke
88 to work its magic. Fortunately, the code it uses is fairly stable across Python versions.

Dòng 5 cũng sử dụng

$ python3 -m pip install invoke
89 để thêm thư mục hiện tại vào danh sách các đường dẫn
$ python3 -m pip install invoke
85. Điều này cho phép dòng
$ python3 -m pip install invoke
91 trong mã trình bao bọc của bạn được giải quyết.

Dòng 6 Chỉ định tên của tệp nguồn của bạn, đó là

$ python3 -m pip install invoke
92. Sau đó, trên dòng 7, bạn thấy một số phép thuật xây dựng khác xảy ra. Dòng này chỉ định tên của tệp đầu ra. Python có một số ý tưởng cụ thể về đặt tên mô -đun, bao gồm phiên bản Python, kiến ​​trúc máy và các chi tiết khác. Python cũng cung cấp một công cụ để giúp đỡ với điều này được gọi là
$ python3 -m pip install invoke
93:
specifies the name of your source file, which is
$ python3 -m pip install invoke
92. Then, on line 7 you see some more build magic happening. This line specifies the name of the output file. Python has some particular ideas on module naming, which include the Python version, the machine architecture, and other details. Python also provides a tool to help with this called
$ python3 -m pip install invoke
93:

$ invoke build-cmult
==================================================
= Building C Library
* Complete
6

Bạn có thể cần sửa đổi lệnh nếu bạn sử dụng một phiên bản Python khác. Kết quả của bạn có thể sẽ thay đổi nếu bạn sử dụng một phiên bản Python khác hoặc đang ở trên một hệ điều hành khác.

Dòng cuối cùng của lệnh xây dựng của bạn, dòng 8, trỏ trình liên kết tại thư viện

$ python3 -m pip install invoke
94 mà bạn đã xây dựng trước đó. Phần
$ python3 -m pip install invoke
95 cho trình liên kết thêm thông tin vào thư viện được chia sẻ để giúp hệ điều hành tìm thấy
$ python3 -m pip install invoke
94 khi chạy. Cuối cùng, bạn sẽ nhận thấy rằng chuỗi này được định dạng với
$ python3 -m pip install invoke
97 và
$ python3 -m pip install invoke
98. Bạn sẽ sử dụng chức năng này một lần nữa khi bạn xây dựng mô -đun ràng buộc Python của mình với
$ python3 -m pip install invoke
99 trong phần tiếp theo.line 8, points the linker at the
$ python3 -m pip install invoke
94 library you built earlier. The
$ python3 -m pip install invoke
95 section tells the linker to add information to the shared library to help the operating system find
$ python3 -m pip install invoke
94 at runtime. Finally, you’ll notice that this string is formatted with the
$ python3 -m pip install invoke
97 and the
$ python3 -m pip install invoke
98. You’ll be using this function again when you build your Python bindings module with
$ python3 -m pip install invoke
99 in the next section.

Chạy lệnh này để xây dựng các ràng buộc của bạn:

$ invoke build-cmult
==================================================
= Building C Library
* Complete
7

Đó là nó! Bạn đã xây dựng các ràng buộc Python của mình với

$ python3 -m pip install invoke
53. Nó thời gian để kiểm tra nó!

Gọi chức năng của bạn

Tương tự như ví dụ

# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 ở trên, một khi bạn đã thực hiện việc nâng cao các ràng buộc Python, gọi chức năng của bạn trông giống như mã Python bình thường:

$ invoke build-cmult
==================================================
= Building C Library
* Complete
8

Vì bạn đã sử dụng

$ python3 -m pip install invoke
72 làm tên của mô -đun của bạn trong macro
$ python3 -m pip install invoke
69, nên tên bạn nhập tên. Trong cuộc gọi
$ python3 -m pip install invoke
75, bạn đã nói
$ python3 -m pip install invoke
53 để xuất hàm
$ python3 -m pip install invoke
80 là
$ python3 -m pip install invoke
76, do đó, những gì bạn sử dụng để gọi nó từ Python.

Bạn cũng có thể kiểm tra nó với

// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2:

$ invoke build-cmult
==================================================
= Building C Library
* Complete
9

Đó là những gì

$ python3 -m pip install invoke
53 trông như thế nào. Tiếp theo, bạn sẽ thấy khi nào và tại sao
$ python3 -m pip install invoke
53 là công cụ phù hợp cho công việc.

Điểm mạnh và điểm yếu

$ python3 -m pip install invoke
53 tập trung vào C ++ thay vì C, điều này làm cho nó khác với
// cmult.h
float cmult(int int_param, float float_param);
1 và
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9. Nó có một số tính năng làm cho nó khá hấp dẫn đối với các thư viện C ++:

  • Nó hỗ trợ các lớp học.classes.
  • Nó xử lý các lớp con đa hình.polymorphic subclassing.
  • Nó cho phép bạn thêm các thuộc tính động vào các đối tượng từ Python và nhiều công cụ khác, điều này sẽ khá khó thực hiện từ các công cụ dựa trên C mà bạn đã kiểm tra.dynamic attributes to objects from Python and many other tools, which would be quite difficult to do from the C-based tools you’ve examined.

Điều đó đang được nói, có một chút thiết lập và cấu hình công bằng bạn cần làm để có được

$ python3 -m pip install invoke
53 lên và chạy. Việc cài đặt và xây dựng chính xác có thể hơi khó tính, nhưng một khi đã hoàn thành, nó có vẻ khá vững chắc. Ngoài ra,
$ python3 -m pip install invoke
53 yêu cầu bạn sử dụng ít nhất C ++ 11 hoặc mới hơn. Điều này khó có thể là một hạn chế lớn cho hầu hết các dự án, nhưng nó có thể là một sự cân nhắc cho bạn.

Cuối cùng, mã bổ sung bạn cần viết để tạo các ràng buộc Python nằm trong C ++ chứ không phải Python. Điều này có thể hoặc không phải là một vấn đề đối với bạn, nhưng nó khác với các công cụ khác mà bạn đã xem xét ở đây. Trong phần tiếp theo, bạn sẽ chuyển sang

$ python3 -m pip install invoke
99, có cách tiếp cận khá khác với vấn đề này.

$ python3 -m pip install invoke 99

Cách tiếp cận

$ python3 -m pip install invoke
99 thực hiện để tạo các ràng buộc Python sử dụng ngôn ngữ giống như Python để xác định các ràng buộc và sau đó tạo mã C hoặc C ++ có thể được biên dịch vào mô-đun. Có một số phương pháp để xây dựng các ràng buộc Python với
$ python3 -m pip install invoke
99. Cái phổ biến nhất là sử dụng
$ invoke build-cmult
==================================================
= Building C Library
* Complete
20 từ
$ invoke build-cmult
==================================================
= Building C Library
* Complete
21. Trong ví dụ này, bạn sẽ gắn bó với công cụ
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2, cho phép bạn chơi với các lệnh chính xác được chạy.Python-like language to define the bindings and then generates C or C++ code that can be compiled into the module. There are several methods for building Python bindings with
$ python3 -m pip install invoke
99. The most common one is to use
$ invoke build-cmult
==================================================
= Building C Library
* Complete
20 from
$ invoke build-cmult
==================================================
= Building C Library
* Complete
21. For this example, you’ll stick with the
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2 tool, which will allow you to play with the exact commands that are run.

Cách nó cài đặt

$ python3 -m pip install invoke
99 là một mô -đun Python có thể được cài đặt vào môi trường ảo của bạn từ PYPI:

$ invoke --list
Available tasks:

  all              Build and run all tests
  build-cffi       Build the CFFI Python bindings
  build-cmult      Build the shared library for the sample C code
  build-cppmult    Build the shared library for the sample C++ code
  build-cython     Build the cython extension module
  build-pybind11   Build the pybind11 wrapper library
  clean            Remove any built objects
  test-cffi        Run the script to test CFFI
  test-ctypes      Run the script to test ctypes
  test-cython      Run the script to test Cython
  test-pybind11    Run the script to test PyBind11
0

Một lần nữa, nếu bạn đã cài đặt tệp

$ python3 -m pip install invoke
04 vào môi trường ảo của bạn, thì điều này sẽ ở đó. Bạn có thể lấy một bản sao của
$ python3 -m pip install invoke
04 bằng cách nhấp vào liên kết bên dưới:

Điều đó nên bạn đã sẵn sàng để làm việc với

$ python3 -m pip install invoke
99!

Gọi chức năng

Để xây dựng các ràng buộc Python của bạn với

$ python3 -m pip install invoke
99, bạn sẽ làm theo các bước tương tự với các bước bạn đã sử dụng cho
# ctypes_test.py
import ctypes
import pathlib

if __name__ == "__main__":
    # Load the shared library into ctypes
    libname = pathlib.Path().absolute() / "libcmult.so"
    c_lib = ctypes.CDLL(libname)
9 và
$ python3 -m pip install invoke
53. Bạn sẽ viết các ràng buộc, xây dựng chúng và sau đó chạy mã Python để gọi chúng.
$ python3 -m pip install invoke
99 có thể hỗ trợ cả C và C ++. Trong ví dụ này, bạn sẽ sử dụng thư viện
$ python3 -m pip install invoke
80 mà bạn đã sử dụng cho ví dụ
$ python3 -m pip install invoke
53 ở trên.

Viết các ràng buộc

Hình thức phổ biến nhất của việc khai báo một mô -đun trong

$ python3 -m pip install invoke
99 là sử dụng tệp
$ invoke build-cmult
==================================================
= Building C Library
* Complete
34:

$ invoke --list
Available tasks:

  all              Build and run all tests
  build-cffi       Build the CFFI Python bindings
  build-cmult      Build the shared library for the sample C code
  build-cppmult    Build the shared library for the sample C++ code
  build-cython     Build the cython extension module
  build-pybind11   Build the pybind11 wrapper library
  clean            Remove any built objects
  test-cffi        Run the script to test CFFI
  test-ctypes      Run the script to test ctypes
  test-cython      Run the script to test Cython
  test-pybind11    Run the script to test PyBind11
1

Có hai phần ở đây:

  1. Dòng 3 và 4 nói với
    $ python3 -m pip install invoke
    
    99 rằng bạn sử dụng
    $ invoke build-cmult
    ==================================================
    = Building C Library
    * Complete
    
    36 từ
    $ python3 -m pip install invoke
    
    68.
    tell
    $ python3 -m pip install invoke
    
    99 that you’re using
    $ invoke build-cmult
    ==================================================
    = Building C Library
    * Complete
    
    36 from
    $ python3 -m pip install invoke
    
    68.
  2. Các dòng 6 và 7 Tạo hàm trình bao bọc,
    $ invoke build-cmult
    ==================================================
    = Building C Library
    * Complete
    
    38, để gọi
    $ invoke build-cmult
    ==================================================
    = Building C Library
    * Complete
    
    36.
    create a wrapper function,
    $ invoke build-cmult
    ==================================================
    = Building C Library
    * Complete
    
    38, to call
    $ invoke build-cmult
    ==================================================
    = Building C Library
    * Complete
    
    36.

Ngôn ngữ được sử dụng ở đây là sự pha trộn đặc biệt của C, C ++ và Python. Tuy nhiên, nó sẽ trông khá quen thuộc với các nhà phát triển Python, vì mục tiêu là làm cho quá trình dễ dàng hơn.

Phần đầu tiên với

$ invoke build-cmult
==================================================
= Building C Library
* Complete
40 nói với
$ python3 -m pip install invoke
99 rằng các khai báo hàm dưới đây cũng được tìm thấy trong tệp
$ python3 -m pip install invoke
68. Điều này rất hữu ích để đảm bảo rằng các ràng buộc python của bạn được xây dựng theo cùng một khai báo với mã C ++ của bạn. Phần thứ hai trông giống như một hàm Python thông thường, vì nó là như vậy! Phần này tạo ra một hàm Python có quyền truy cập vào hàm C ++
$ python3 -m pip install invoke
80.

Bây giờ bạn đã có các ràng buộc Python được xác định, đó là thời gian để xây dựng chúng!

Xây dựng các ràng buộc Python

Quá trình xây dựng cho

$ python3 -m pip install invoke
99 có điểm tương đồng với quy trình bạn đã sử dụng cho
$ python3 -m pip install invoke
53. Trước tiên, bạn chạy
$ python3 -m pip install invoke
99 trên tệp
$ invoke build-cmult
==================================================
= Building C Library
* Complete
34 để tạo tệp
$ invoke build-cmult
==================================================
= Building C Library
* Complete
48. Khi bạn đã thực hiện việc này, bạn biên dịch nó với cùng một chức năng bạn đã sử dụng cho
$ python3 -m pip install invoke
53:

$ invoke --list
Available tasks:

  all              Build and run all tests
  build-cffi       Build the CFFI Python bindings
  build-cmult      Build the shared library for the sample C code
  build-cppmult    Build the shared library for the sample C++ code
  build-cython     Build the cython extension module
  build-pybind11   Build the pybind11 wrapper library
  clean            Remove any built objects
  test-cffi        Run the script to test CFFI
  test-ctypes      Run the script to test ctypes
  test-cython      Run the script to test Cython
  test-pybind11    Run the script to test PyBind11
2

Bạn bắt đầu bằng cách chạy

$ invoke build-cmult
==================================================
= Building C Library
* Complete
50 trên tệp
$ invoke build-cmult
==================================================
= Building C Library
* Complete
34 của bạn. Có một vài tùy chọn bạn sử dụng trên lệnh này:

  • $ invoke build-cmult
    ==================================================
    = Building C Library
    * Complete
    
    52 yêu cầu trình biên dịch tạo tệp C ++ thay vì tệp C.
    tells the compiler to generate a C++ file instead of a C file.
  • $ invoke build-cmult
    ==================================================
    = Building C Library
    * Complete
    
    53 Chuyển đổi
    $ python3 -m pip install invoke
    
    99 để tạo cú pháp Python 3 thay vì Python 2.
    switches
    $ python3 -m pip install invoke
    
    99 to generate Python 3 syntax instead of Python 2.
  • $ invoke build-cmult
    ==================================================
    = Building C Library
    * Complete
    
    55 Chỉ định tên của tệp để tạo.
    specifies the name of the file to generate.

Khi tệp C ++ được tạo, bạn sử dụng trình biên dịch C ++ để tạo các ràng buộc Python, giống như bạn đã làm cho

$ python3 -m pip install invoke
53. Lưu ý rằng cuộc gọi để tạo ra các đường dẫn
$ python3 -m pip install invoke
85 thêm bằng công cụ
$ python3 -m pip install invoke
84 vẫn còn trong chức năng đó. Nó đã thắng được bất cứ điều gì ở đây, vì nguồn của bạn sẽ không cần những thứ đó.

Chạy nhiệm vụ này trong

// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2 tạo ra đầu ra này:

$ invoke --list
Available tasks:

  all              Build and run all tests
  build-cffi       Build the CFFI Python bindings
  build-cmult      Build the shared library for the sample C code
  build-cppmult    Build the shared library for the sample C++ code
  build-cython     Build the cython extension module
  build-pybind11   Build the pybind11 wrapper library
  clean            Remove any built objects
  test-cffi        Run the script to test CFFI
  test-ctypes      Run the script to test ctypes
  test-cython      Run the script to test Cython
  test-pybind11    Run the script to test PyBind11
3

Bạn có thể thấy rằng nó xây dựng thư viện

$ python3 -m pip install invoke
80 và sau đó xây dựng mô -đun
$ invoke build-cmult
==================================================
= Building C Library
* Complete
50 để bọc nó. Bây giờ bạn có các ràng buộc python
$ python3 -m pip install invoke
99. (Hãy thử nói điều đó một cách nhanh chóng) Đó là thời gian để kiểm tra nó!

Gọi chức năng của bạn

Mã Python để gọi các ràng buộc Python mới của bạn khá giống với những gì bạn đã sử dụng để kiểm tra các mô -đun khác:

$ invoke --list
Available tasks:

  all              Build and run all tests
  build-cffi       Build the CFFI Python bindings
  build-cmult      Build the shared library for the sample C code
  build-cppmult    Build the shared library for the sample C++ code
  build-cython     Build the cython extension module
  build-pybind11   Build the pybind11 wrapper library
  clean            Remove any built objects
  test-cffi        Run the script to test CFFI
  test-ctypes      Run the script to test ctypes
  test-cython      Run the script to test Cython
  test-pybind11    Run the script to test PyBind11
4

Dòng 2 nhập mô -đun ràng buộc Python mới của bạn và bạn gọi

$ invoke build-cmult
==================================================
= Building C Library
* Complete
38 trên dòng 7. Hãy nhớ rằng tệp
$ invoke build-cmult
==================================================
= Building C Library
* Complete
34 đã cung cấp một trình bao bọc Python vào khoảng
$ invoke build-cmult
==================================================
= Building C Library
* Complete
36 và đổi tên thành
$ invoke build-cmult
==================================================
= Building C Library
* Complete
66. Sử dụng Gọi để chạy bài kiểm tra của bạn tạo ra như sau:

$ invoke --list
Available tasks:

  all              Build and run all tests
  build-cffi       Build the CFFI Python bindings
  build-cmult      Build the shared library for the sample C code
  build-cppmult    Build the shared library for the sample C++ code
  build-cython     Build the cython extension module
  build-pybind11   Build the pybind11 wrapper library
  clean            Remove any built objects
  test-cffi        Run the script to test CFFI
  test-ctypes      Run the script to test ctypes
  test-cython      Run the script to test Cython
  test-pybind11    Run the script to test PyBind11
5

Bạn nhận được kết quả tương tự như trước đây!

Điểm mạnh và điểm yếu

$ python3 -m pip install invoke
99 là một công cụ tương đối phức tạp có thể cung cấp cho bạn mức độ kiểm soát sâu sắc khi tạo các ràng buộc Python cho C hoặc C ++. Mặc dù bạn đã không bao gồm nó theo chiều sâu ở đây, nhưng nó cung cấp một phương pháp Python-esque để viết mã kiểm soát thủ công GIL, có thể tăng tốc đáng kể một số loại vấn đề.a deep level of control when creating Python bindings for either C or C++. Though you didn’t cover it in depth here, it provides a Python-esque method for writing code that manually controls the GIL, which can significantly speed up certain types of problems.

Tuy nhiên, ngôn ngữ Python-esque đó không hoàn toàn là Python, vì vậy, có một đường cong học tập nhẹ khi bạn đang đến tốc độ trong việc tìm ra phần nào của C và Python vừa vặn ở đâu.

Các giải pháp khác

Trong khi nghiên cứu hướng dẫn này, tôi đã bắt gặp một số công cụ và tùy chọn khác nhau để tạo các ràng buộc Python. Mặc dù tôi giới hạn tổng quan này cho một số tùy chọn phổ biến hơn, có một số công cụ khác tôi tình cờ thấy. Danh sách dưới đây không toàn diện. Nó chỉ đơn thuần là một mẫu của các khả năng khác nếu một trong những công cụ trên không phù hợp với dự án của bạn.

$ invoke build-cmult ================================================== = Building C Library * Complete 68

$ invoke build-cmult
==================================================
= Building C Library
* Complete
68 tạo ra các ràng buộc Python cho C hoặc C ++ và được viết bằng Python. Nó nhắm mục tiêu vào việc sản xuất mã C hoặc C ++ có thể đọc được, điều này sẽ đơn giản hóa các vấn đề gỡ lỗi. Rõ ràng nếu điều này đã được cập nhật gần đây, vì tài liệu liệt kê Python 3.4 là phiên bản được thử nghiệm mới nhất. Tuy nhiên, đã có các bản phát hành hàng năm trong vài năm qua. generates Python bindings for C or C++ and is written in Python. It’s targeted at producing readable C or C++ code, which should simplify debugging issues. It wasn’t clear if this has been updated recently, as the documentation lists Python 3.4 as the latest tested version. There have been yearly releases for the last several years, however.

$ invoke build-cmult ================================================== = Building C Library * Complete 70

$ invoke build-cmult
==================================================
= Building C Library
* Complete
70 có giao diện tương tự như
$ python3 -m pip install invoke
53, mà bạn đã thấy ở trên. Đó không phải là một sự trùng hợp ngẫu nhiên, vì
$ python3 -m pip install invoke
53 dựa trên thư viện này!
$ invoke build-cmult
==================================================
= Building C Library
* Complete
70 được viết bằng C ++ đầy đủ và hỗ trợ hầu hết, nếu không phải tất cả, các phiên bản của C ++ trên hầu hết các nền tảng. Ngược lại,
$ python3 -m pip install invoke
53 tự hạn chế C ++ hiện đại.
has an interface similar to
$ python3 -m pip install invoke
53, which you saw above. That’s not a coincidence, as
$ python3 -m pip install invoke
53 was based on this library!
$ invoke build-cmult
==================================================
= Building C Library
* Complete
70 is written in full C++ and supports most, if not all, versions of C++ on most platforms. In contrast,
$ python3 -m pip install invoke
53 restricts itself to modern C++.

$ invoke build-cmult ================================================== = Building C Library * Complete 76

$ invoke build-cmult
==================================================
= Building C Library
* Complete
76 là một bộ công cụ để tạo các ràng buộc python được phát triển cho dự án PYQT. Nó cũng được sử dụng bởi dự án Wxpython để tạo ra các ràng buộc của họ. Nó có một công cụ tạo mã và một mô -đun Python bổ sung cung cấp các chức năng hỗ trợ cho mã được tạo. is a toolset for generating Python bindings that was developed for the PyQt project. It’s also used by the wxPython project to generate their bindings, as well. It has a code generation tool and an extra Python module that provides support functions for the generated code.

$ invoke build-cmult ================================================== = Building C Library * Complete 78

$ invoke build-cmult
==================================================
= Building C Library
* Complete
79 là một công cụ thú vị có mục tiêu thiết kế hơi khác so với những gì bạn đã thấy cho đến nay. Theo lời của gói tác giả: is an interesting tool that has a slightly different design goal than what you’ve seen so far. In the words of the package author:

Ý tưởng ban đầu đằng sau CPPYY (quay trở lại năm 2001), là cho phép các lập trình viên Python sống trong một thế giới C ++ truy cập vào các gói C ++ đó, ​​mà không cần phải chạm trực tiếp C ++ (hoặc chờ đợi các nhà phát triển C ++ xuất hiện và cung cấp các ràng buộc) . ” (Nguồn)

$ invoke build-cmult ================================================== = Building C Library * Complete 80

$ invoke build-cmult
==================================================
= Building C Library
* Complete
80 là một công cụ để tạo ra các ràng buộc python mà đã phát triển cho dự án pyside liên quan đến dự án QT. Mặc dù nó được thiết kế như một công cụ cho dự án đó, nhưng tài liệu chỉ ra rằng nó không phải là QT- hay pyside cụ thể và có thể sử dụng cho các dự án khác. is a tool for generating Python bindings that’s developed for the PySide project associated with the Qt project. While it was designed as a tool for that project, the documentation indicates that it’s neither Qt- nor PySide-specific and is usable for other projects.

$ invoke build-cmult ================================================== = Building C Library * Complete 82

$ invoke build-cmult
==================================================
= Building C Library
* Complete
82 là một công cụ khác với bất kỳ công cụ nào khác được liệt kê ở đây. Nó là một công cụ chung được sử dụng để tạo các liên kết với các chương trình C và C ++ cho nhiều ngôn ngữ khác, không chỉ Python. Khả năng tạo ra các ràng buộc này cho các ngôn ngữ khác nhau có thể khá hữu ích trong một số dự án. Tất nhiên, nó đi kèm với một chi phí liên quan đến sự phức tạp. is a different tool than any of the others listed here. It’s a general tool used to create bindings to C and C++ programs for many other languages, not just Python. This ability to generate bindings for different languages can be quite useful in some projects. It, of course, comes with a cost as far as complexity is concerned.

Sự kết luận

Chúc mừng! Bây giờ bạn đã có một cái nhìn tổng quan về một số tùy chọn khác nhau để tạo các ràng buộc Python. Bạn đã học về dữ liệu sắp xếp và các vấn đề bạn cần xem xét khi tạo các ràng buộc. Bạn đã thấy những gì nó cần để có thể gọi hàm C hoặc C ++ từ Python bằng cách sử dụng các công cụ sau:Python bindings. You’ve learned about marshalling data and issues you need to consider when creating bindings. You’ve seen what it takes to be able to call a C or C++ function from Python using the following tools:

  • // cmult.h
    float cmult(int int_param, float float_param);
    
    1
  • # ctypes_test.py
    import ctypes
    import pathlib
    
    if __name__ == "__main__":
        # Load the shared library into ctypes
        libname = pathlib.Path().absolute() / "libcmult.so"
        c_lib = ctypes.CDLL(libname)
    
    9
  • $ python3 -m pip install invoke
    
    53
  • $ python3 -m pip install invoke
    
    99

Bây giờ bạn biết rằng, trong khi

// cmult.h
float cmult(int int_param, float float_param);
1 cho phép bạn tải trực tiếp thư viện DLL hoặc chia sẻ, ba công cụ khác có thêm một bước, nhưng vẫn tạo một mô -đun Python đầy đủ. Như một phần thưởng, bạn cũng đã chơi một chút với công cụ
// cmult.c
float cmult(int int_param, float float_param) {
    float return_value = int_param * float_param;
    printf("    In cmult : int: %d float %.1f returning  %.1f\n", int_param,
            float_param, return_value);
    return return_value;
}
2 để chạy các tác vụ dòng lệnh từ Python. Bạn có thể nhận được tất cả các mã bạn đã thấy trong hướng dẫn này bằng cách nhấp vào liên kết bên dưới:

Bây giờ chọn công cụ yêu thích của bạn và bắt đầu xây dựng các ràng buộc Python đó! Đặc biệt cảm ơn Loic Domaigne cho đánh giá kỹ thuật bổ sung của hướng dẫn này.Loic Domaigne for the extra technical review of this tutorial.

Python có thể tương tác với C không?

Nói chung, mã C đã viết sẽ không yêu cầu sửa đổi được sử dụng bởi Python. Công việc duy nhất chúng ta cần làm để tích hợp mã C vào Python là về phía Python. Các bước để giao tiếp với Python với C bằng cách sử dụng CTYPE.already-written C code will require no modifications to be used by Python. The only work we need to do to integrate C code in Python is on Python's side. The steps for interfacing Python with C using Ctypes.

Hàm C trong Python là gì?

Bạn nên gọi C từ Python bằng cách viết trình bao bọc Ctypes. Cython là để làm cho mã giống như Python chạy nhanh hơn, CTYPES là để tạo các chức năng C có thể gọi được từ Python. Những gì bạn cần làm là như sau: Viết các chức năng C bạn muốn sử dụng.

Làm cách nào để kết nối với Python và C?

Có một số cách để làm điều này.Cách đơn giản nhất, đơn giản nhất là sử dụng API Python C và viết một trình bao bọc cho thư viện C của bạn có thể được gọi từ Python.Điều này gắn mô -đun của bạn với Cpython.Cách thứ hai là sử dụng CTYPE là FFI cho Python cho phép bạn tải và gọi các chức năng trong các thư viện C.use the Python C API and write a wrapper for your C library which can be called from Python. This ties your module to CPython. The second way is to use ctypes which is an FFI for Python that allows you to load and call functions in C libraries directly.

Python có thể nhập các tệp C không?

CTYPES cho phép bạn tải thư viện C đã tồn tại trực tiếp vào chương trình Python của bạn.CFFI, mặt khác, tạo ra một mô -đun Python mới có thể được tải như các mô -đun Python khác.. CFFI , on the other hand, creates a new Python module that can be loaded like other Python modules.