C++ gọi hàm Python có đối số

Một cuộc gọi được thực hiện bằng cách sử dụng một bộ cho các đối số vị trí và một lệnh cho các đối số từ khóa, tương tự như

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
4 trong mã Python. đối số phải không phải là NULL (sử dụng bộ dữ liệu trống nếu không có đối số) nhưng kwargs có thể là NULL nếu không có đối số từ khóa

Quy ước này không chỉ được sử dụng bởi tp_call.

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
5 và
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
6 cũng truyền đối số theo cách này

Để gọi một đối tượng, hãy sử dụng

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
7 hoặc API gọi khác.

Giao thức Vectorcall¶

Mới trong phiên bản 3. 9

Giao thức vectorcall được giới thiệu trong PEP 590 như một giao thức bổ sung để thực hiện cuộc gọi hiệu quả hơn

Theo nguyên tắc thông thường, CPython sẽ thích gọi vector hơn cho các cuộc gọi nội bộ nếu có thể gọi được hỗ trợ nó. Tuy nhiên, đây không phải là một quy tắc cứng. Ngoài ra, một số tiện ích mở rộng của bên thứ ba sử dụng trực tiếp tp_call (thay vì sử dụng

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
7). Do đó, một lớp hỗ trợ vectorcall cũng phải triển khai
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
9. Hơn nữa, khả năng gọi được phải hoạt động giống nhau bất kể giao thức nào được sử dụng. Cách được khuyến nghị để đạt được điều này là đặt
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
9 thành
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
0. Điều này lặp đi lặp lại

Cảnh báo

Một lớp hỗ trợ gọi vector cũng phải triển khai

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
9 với cùng ngữ nghĩa

Một lớp không nên triển khai vectorcall nếu điều đó chậm hơn tp_call. Ví dụ: nếu callee cần chuyển đổi các đối số thành args Tuple và kwargs dict dù sao đi nữa, thì không có điểm nào trong việc triển khai vectorcall

Các lớp có thể triển khai giao thức gọi vector bằng cách bật cờ

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
2 và đặt
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
3 thành phần bù bên trong cấu trúc đối tượng nơi xuất hiện vectorcallfunc. Đây là một con trỏ tới một hàm có chữ ký sau

typedef PyObject *(*vectorcallfunc)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
  • callable is the object being called.

  • args là một mảng C bao gồm các đối số vị trí theo sau là

    giá trị của các đối số từ khóa. Đây có thể là NULL nếu không có đối số

  • nargsf là số đối số vị trí cộng với có thể là

    cờ

    (Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
    
    4. Để có được số lượng đối số vị trí thực tế từ nargsf, hãy sử dụng
    (Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
    
    5

  • kwnames là một bộ chứa tên của các đối số từ khóa;

    nói cách khác, các phím của kwargs dict. Những tên này phải là chuỗi (ví dụ của

    (Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
    
    6 hoặc một lớp con) và chúng phải là duy nhất. Nếu không có đối số từ khóa, thì kwnames có thể thay thế bằng NULL

PY_VECTORCALL_ARGUMENTS_OFFSET

Nếu cờ này được đặt trong đối số nargsf của cuộc gọi vector, thì callee được phép tạm thời thay đổi

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
7. Nói cách khác, args trỏ đến đối số 1 (không phải 0) trong vectơ được phân bổ. Callee phải khôi phục giá trị của
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
7 trước khi quay lại.

Đối với

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
9, thay vào đó, cờ này có nghĩa là
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
90 có thể được thay đổi

Bất cứ khi nào họ có thể làm như vậy với chi phí thấp (không cần phân bổ thêm), người gọi được khuyến khích sử dụng

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
4. Làm như vậy sẽ cho phép các phương thức có thể gọi được, chẳng hạn như các phương thức bị ràng buộc, thực hiện các cuộc gọi tiếp theo của chúng (bao gồm một đối số self được thêm vào trước) rất hiệu quả

Để gọi một đối tượng triển khai vectorcall, hãy sử dụng hàm gọi API như với bất kỳ chức năng gọi nào khác.

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
92 thường sẽ hiệu quả nhất.

Ghi chú

Trong CPython 3. 8, API vectorcall và các chức năng liên quan tạm thời có sẵn dưới các tên có dấu gạch dưới ở đầu.

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
93,
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
94,
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
95,
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
96,
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
97,
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
98,
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
99. Ngoài ra,
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
40 có sẵn dưới dạng
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
41. Tên cũ vẫn được định nghĩa là bí danh của tên mới, không được gạch dưới

Kiểm soát đệ quy¶

Khi sử dụng tp_call, callees không cần lo lắng về đệ quy . Python sử dụng ________ 142 và ________ 143 cho các cuộc gọi được thực hiện bằng tp_call.

Để đạt hiệu quả, đây không phải là trường hợp đối với các cuộc gọi được thực hiện bằng vectorcall. callee nên sử dụng Py_EnterRecursiveCall và Py_LeaveRecursiveCall nếu cần

API hỗ trợ Vectorcall¶

Py_ssize_t PyVectorcall_NARGS(size_t nargsf)

Given a vectorcall nargsf argument, return the actual number of arguments. Currently equivalent to:

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)

Tuy nhiên, chức năng

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
44 nên được sử dụng để cho phép mở rộng trong tương lai

Mới trong phiên bản 3. 8

vectorcallfunc PyVectorcall_Function(PyObject *op)

If op does not support the vectorcall protocol (either because the type does not or because the specific instance does not), return NULL. Otherwise, return the vectorcall function pointer stored in op. This function never raises an exception.

Điều này chủ yếu hữu ích để kiểm tra xem op có hỗ trợ vectorcall hay không, điều này có thể được thực hiện bằng cách kiểm tra

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
45

Mới trong phiên bản 3. 8

PyObject *PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict)

Call callable’s

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
46 with positional and keyword arguments given in a tuple and dict, respectively.

Đây là một chức năng chuyên biệt, được thiết kế để đưa vào khe cắm

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
9 hoặc được sử dụng để triển khai
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
9. Nó không kiểm tra cờ
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
2 và nó không rơi trở lại
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
9

Mới trong phiên bản 3. 8

API gọi đối tượng¶

Nhiều chức năng có sẵn để gọi một đối tượng Python. Mỗi chuyển đổi các đối số của nó thành một quy ước được hỗ trợ bởi đối tượng được gọi – tp_call hoặc vectorcall. Để thực hiện ít chuyển đổi nhất có thể, hãy chọn một chuyển đổi phù hợp nhất với định dạng dữ liệu bạn có sẵn

Bảng sau đây tóm tắt các chức năng có sẵn;

Hàm số

gọi được

tranh luận

kwargs

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
7

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
52

tuple

dict/______153

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
54

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
52

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
56

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
52

1 đối tượng

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
58

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
52

tuple/

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
53

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
61

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
52

định dạng

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
63

đối tượng +

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
64

định dạng

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
65

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
52

biến thiên

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
67

đối tượng + tên

biến thiên

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
68

đối tượng + tên

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
69

đối tượng + tên

1 đối tượng

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
92

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
52

cuộc gọi vector

cuộc gọi vector

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
72

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
52

cuộc gọi vector

dict/______153

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
9

đối số + tên

cuộc gọi vector

cuộc gọi vector

PyObject *PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
Return value: New reference. Part of the ABI ổn định .

Gọi một đối tượng Python có thể gọi được có thể gọi được, với các đối số được cung cấp bởi tuple args và các đối số được đặt tên được cung cấp bởi từ điển kwargs

đối số không được NULL; . Nếu không cần đối số được đặt tên, kwarg có thể là NULL

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

Điều này tương đương với biểu thức Python.

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
4

PyObject *PyObject_CallNoArgs(PyObject *callable)
Part of the Stable ABI since version 3.10.

Gọi một đối tượng Python có thể gọi được có thể gọi được mà không cần bất kỳ đối số nào. Đây là cách hiệu quả nhất để gọi một đối tượng Python có thể gọi được mà không cần bất kỳ đối số nào

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

Mới trong phiên bản 3. 9

PyObject *PyObject_CallOneArg(PyObject *callable, PyObject *arg)

Call a callable Python object callable with exactly 1 positional argument arg and no keyword arguments.

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

Mới trong phiên bản 3. 9

PyObject *PyObject_CallObject(PyObject *callable, PyObject *args)
Return value: New reference. Part of the ABI ổn định .

Gọi một đối tượng Python có thể gọi được có thể gọi được, với các đối số được cung cấp bởi tuple args. Nếu không cần đối số, thì đối số có thể là NULL

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

Điều này tương đương với biểu thức Python.

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
77

PyObject *PyObject_CallFunction(PyObject *callable, const char *format, ...)
Giá trị trả về. Tài liệu tham khảo mới. Một phần của ABI ổn định .

Gọi một đối tượng Python có thể gọi được có thể gọi được, với số lượng đối số C thay đổi. Các đối số C được mô tả bằng chuỗi định dạng kiểu

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
78. Định dạng có thể là NULL, cho biết rằng không có đối số nào được cung cấp

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

Điều này tương đương với biểu thức Python.

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
77

Lưu ý rằng nếu bạn chỉ vượt qua PyObject* lập luận, thì

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
65 là giải pháp thay thế nhanh hơn.

Đã thay đổi trong phiên bản 3. 4. Loại định dạng đã được thay đổi từ

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
71.

PyObject *PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...)
Giá trị trả về. Tài liệu tham khảo mới. Một phần của ABI ổn định .

Gọi phương thức có tên là tên của đối tượng obj với số lượng đối số C thay đổi. Các đối số C được mô tả bằng một chuỗi định dạng

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
78 sẽ tạo ra một bộ

Định dạng có thể là NULL, cho biết rằng không có đối số nào được cung cấp

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

Điều này tương đương với biểu thức Python.

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
73

Lưu ý rằng nếu bạn chỉ vượt qua PyObject* đối số, thì

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
67 là giải pháp thay thế nhanh hơn.

Đã thay đổi trong phiên bản 3. 4. Các loại tên và định dạng đã được thay đổi từ

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
71.

PyObject *PyObject_CallFunctionObjArgs(PyObject *callable, ...)
Giá trị trả về. Tài liệu tham khảo mới. Một phần của ABI ổn định .

Gọi một đối tượng Python có thể gọi được có thể gọi được, với số lượng biến PyObject* đối số. Các đối số được cung cấp dưới dạng một số tham số thay đổi theo sau là NULL.

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

Điều này tương đương với biểu thức Python.

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
76

PyObject *PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...)
Giá trị trả về. Tài liệu tham khảo mới. Một phần của ABI ổn định .

Gọi phương thức của đối tượng Python obj, trong đó tên của phương thức được cung cấp dưới dạng đối tượng chuỗi Python trong tên. Nó được gọi với một số lượng biến PyObject* đối số. Các đối số được cung cấp dưới dạng một số tham số thay đổi theo sau là NULL.

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

PyObject *PyObject_CallMethodNoArgs(PyObject *obj, PyObject *name)

Call a method of the Python object obj without arguments, where the name of the method is given as a Python string object in name.

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

Mới trong phiên bản 3. 9

PyObject *PyObject_CallMethodOneArg(PyObject *obj, PyObject *name, PyObject *arg)

Call a method of the Python object obj with a single positional argument arg, where the name of the method is given as a Python string object in name.

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

Mới trong phiên bản 3. 9

PyObject *PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)

Call a callable Python object callable. The arguments are the same as for

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
46. If callable supports vectorcall, this directly calls the vectorcall function stored in callable.

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

Mới trong phiên bản 3. 9

PyObject *PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwdict)

Call callable with positional arguments passed exactly as in the vectorcall protocol, but with keyword arguments passed as a dictionary kwdict. The args array contains only the positional arguments.

Bất kể giao thức nào được sử dụng nội bộ, việc chuyển đổi các đối số cần được thực hiện. Do đó, chức năng này chỉ nên được sử dụng nếu người gọi đã có sẵn một từ điển để sử dụng cho các đối số từ khóa, nhưng không phải là một bộ cho các đối số vị trí

Mới trong phiên bản 3. 9

PyObject *PyObject_VectorcallMethod(PyObject *name, PyObject *const *args, size_t nargsf, PyObject *kwnames)

Call a method using the vectorcall calling convention. The name of the method is given as a Python string name. The object whose method is called is args[0], and the args array starting at args[1] represents the arguments of the call. There must be at least one positional argument. nargsf is the number of positional arguments including args[0], plus

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
4 if the value of
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
90 may temporarily be changed. Keyword arguments can be passed just like in
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
92.

Nếu đối tượng có tính năng

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
91, điều này sẽ gọi đối tượng phương thức không liên kết với vectơ đối số đầy đủ làm đối số

Trả về kết quả của lệnh gọi khi thành công hoặc đưa ra một ngoại lệ và trả về NULL nếu thất bại

Mới trong phiên bản 3. 9

API hỗ trợ cuộc gọi¶

int PyCallable_Check(PyObject *o)
Part of the Stable ABI.

Xác định xem đối tượng o có thể gọi được không. Trả lại

(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
92 nếu đối tượng có thể gọi được và ngược lại là
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
93. Chức năng này luôn thành công

Làm cách nào chúng ta có thể truyền đối số trong lệnh gọi hàm trong Python?

Thông tin có thể được truyền vào hàm dưới dạng đối số. Các đối số được chỉ định sau tên hàm, bên trong dấu ngoặc đơn . Bạn có thể thêm bao nhiêu đối số tùy thích, chỉ cần phân tách chúng bằng dấu phẩy.

Tôi có thể gọi hàm Python trong C không?

Sau đó, khi đến lúc gọi hàm, bạn gọi hàm C PyEval_CallObject() . Hàm này có hai đối số, cả hai đều trỏ tới các đối tượng Python tùy ý. hàm Python và danh sách đối số. Danh sách đối số phải luôn là một đối tượng tuple, có độ dài bằng số lượng đối số.

Làm cách nào để gọi mã Python từ mã C?

Vì vậy, chúng ta sẽ sử dụng quy tắc sau để gọi hàm Python. .
Khởi tạo môi trường Python
Nhập mô-đun Python
Lấy tham chiếu đến hàm Python, để gọi
Kiểm tra xem chức năng có thể được gọi hay không và gọi nó
Sau đó phản đối đối tượng Python được trả về, được trả về bởi hàm, sau khi thực thi

Python có thể lấy các hàm làm đối số không?

Một hàm có thể nhận nhiều đối số , các đối số này có thể là đối tượng, biến (cùng hoặc khác kiểu dữ liệu) và hàm.