Trong Python, Extension cho phép bạn mở rộng khả năng của ngôn ngữ này bằng cách tích hợp mã C/C++ vào trong các dự án Python. Việc này giúp cải thiện hiệu suất và tận dụng được sức mạnh của các thư viện hệ thống đã có. Bài viết này sẽ hướng dẫn bạn về các khái niệm cơ bản, điều kiện cần có, cũng như cách xây dựng và sử dụng Extension trong Python để tối ưu hóa ứng dụng của bạn. Chúng ta sẽ cùng tìm hiểu các bước từ cài đặt, sử dụng cho đến các kỹ thuật xử lý tham số hiệu quả.
Điểm chính cần nắm
- Further Extension trong Python là gì?: Extension trong Python là cách mở rộng các chức năng của Python bằng C/C++ để tối ưu hiệu suất.
- Điều kiện tiên quyết để viết extension: Cần cài đặt Python và trình biên dịch C/C++, hiểu Python C API, sử dụng setuptools và có kiến thức về C/C++.
- Tổng quan về một extension trong Python: Extension trong Python bao gồm các thành phần như file header Python.h, hàm C, phương thức mapping table và hàm khởi tạo module.
- Xây dựng và cài đặt extension: Hướng dẫn chi tiết về cách xây dựng và cài đặt một extension trong Python.
- Import và sử dụng extension trong Python: Cách thức import và sử dụng extension sau khi cài đặt.
- Truyền tham số vào function trong extension: Hướng dẫn cách truyền tham số vào các hàm C trong extension của Python.
- Trích xuất tham số bằng pyarg_parsetuple: Giới thiệu về việc sử dụng PyArg_ParseTuple để xử lý tham số truyền vào.
- Hàm Py_BuildValue – Trả về giá trị từ extension: Cách sử dụng hàm Py_BuildValue để trả về giá trị từ extension trong Python.
- Vietnix – Nhà cung cấp dịch vụ lưu trữ uy tín, tốc độ và bảo mật hàng đầu: Giới thiệu Vietnix như một nhà cung cấp dịch vụ hosting, server và VPS đáng tin cậy tại Việt Nam.
- FAQ: Phần câu hỏi thường gặp, giải đáp các thắc mắc về việc sử dụng Extension trong Python.
Further Extension trong Python là gì?
Further Extensions trong Python là cách mở rộng khả năng của Python bằng cách tích hợp mã từ các ngôn ngữ lập trình khác như C, C++ hoặc Java. Điều này giúp cải thiện hiệu suất và bổ sung các chức năng mà Python thuần không có. Các phần mở rộng này thường được viết dưới dạng module C và có thể biên dịch thành thư viện chia sẻ. Trên Unix, các thư viện này có đuôi .so
(shared object), còn trên Windows, chúng có đuôi .dll
(dynamically linked library).

Điều kiện tiên quyết để viết extension
1. Cài đặt Python và trình biên dịch C/C++
2. Hiểu về Python C API
3. Biết cách sử dụng setuptools
4. Kiến thức về C/C++
5. Biết cách biên dịch module mở rộng
1. Cài đặt Python và trình biên dịch C/C++
- Đảm bảo đã cài đặt Python (Nên dùng phiên bản mới nhất).
- Cài đặt trình biên dịch:
2. Hiểu về Python C API
Python C API cung cấp các hàm giúp thao tác với đối tượng Python từ C/C++. Việc hiểu rõ API này giúp:
- Giúp tối ưu hiệu suất khi viết extension.
- Quản lý bộ nhớ hiệu quả.
- Xử lý lỗi chính xác.
3. Biết cách sử dụng setuptools
setuptools
hỗ trợ biên dịch và đóng gói extension một cách đơn giản. Cài đặt bằng lệnh:
pip install setuptools
Ngoài ra, bạn cần hiểu cách sử dụng các function trong module mở rộng, ví dụ:
static PyObject *MyFunction(PyObject *self, PyObject *args);
static PyObject *MyFunctionWithKeywords(PyObject *self, PyObject *args, PyObject *kw);
static PyObject *MyFunctionWithNoArgs(PyObject *self);
4. Kiến thức về C/C++
Cần có hiểu biết về:
- Con trỏ và quản lý bộ nhớ.
- Cách tạo và sử dụng thư viện động (
.so
trên Linux/macOS,.dll
trên Windows).
5. Biết cách biên dịch module mở rộng
- Viết mã C để định nghĩa các hàm có thể gọi từ Python.
- Sử dụng
setup.py
để biên dịch thành thư viện mở rộng có thể nhập vào Python.
Ngoài ra, để bắt đầu viết extension, bạn cần có các tệp tiêu đề của Python.
- Trên Linux/macOS: Cần cài đặt thêm gói dành cho nhà phát triển (ví dụ:
python3-dev
trên Debian/Ubuntu). - Trên Windows: Các tệp tiêu đề này có sẵn khi cài đặt Python dưới dạng nhị phân.
Cuối cùng, kiến thức vững chắc về C hoặc C++ là điều bắt buộc nếu muốn viết extension cho Python.
Tổng quan về một extension trong Python
Một extension trong Python là một module được viết bằng C hoặc C++, giúp mở rộng chức năng của Python, tối ưu hiệu suất hoặc tích hợp với thư viện bên ngoài. Extension thường được biên dịch thành thư viện động (.so
trên Linux/macOS, .dll
trên Windows) và có thể được import như một module Python thông thường.
Một module mở rộng trong Python thường bao gồm bốn phần chính:
- File header
Python.h
: Cung cấp các định nghĩa cần thiết để làm việc với Python C API. - Các hàm C/C++: Chứa các logic xử lý mà Python có thể gọi.
- Bảng ánh xạ hàm: Liên kết tên hàm trong Python với các hàm C/C++ tương ứng.
- Hàm khởi tạo module: Được gọi khi module được import vào Python.
File header Python.h
trong extension Python
Python.h
là tệp tiêu đề quan trọng khi viết extension bằng C/C++ cho Python. Tệp này cung cấp các định nghĩa, kiểu dữ liệu và hàm cần thiết để làm việc với Python C API.
Lý do cần Python.h
- Cung cấp quyền truy cập vào Python C API để thao tác với đối tượng Python.
- Hỗ trợ quản lý bộ nhớ của Python, giúp tạo và hủy đối tượng an toàn.
- Cung cấp macro và hàm để xử lý Exception, gọi Function, và tương tác với Module Python.
Cách sử dụng Python.h
Khi viết extension, tệp này cần được bao gồm ở đầu chương trình:
#include <Python.h>
Tệp Python.h
cung cấp quyền truy cập vào API nội bộ của Python, giúp kết nối module C với trình thông dịch. Để tránh lỗi, hãy luôn bao gồm Python.h
trước bất kỳ tiêu đề nào khác trong mã nguồn C. Sau đó, bạn có thể định nghĩa các hàm để gọi từ Python.
Hàm C trong extension
Khi viết extension bằng C, bạn cần định nghĩa các hàm có thể được gọi từ Python. Những hàm này có định dạng đặc biệt để tương thích với Python C API.
Định dạng hàm C trong extension Python
Một hàm C trong extension Python thường có dạng sau:
static PyObject* function_name(PyObject *self, PyObject *args) {
// Xử lý tham số từ Python
// Thực hiện logic của hàm
// Trả về kết quả dưới dạng PyObject*
}
PyObject*
là kiểu trả về chung cho mọi hàm trong module mở rộng.self
: Thường được sử dụng trong phương thức của một object, nhưng với hàm thông thường, nó có thể bỏ qua.args
: Chứa danh sách đối số được truyền từ Python.
Ví dụ hàm C đơn giản
Hàm sau nhận hai số từ Python và trả về tổng của chúng:
#include <Python.h>
static PyObject* add(PyObject *self, PyObject *args) {
int a, b;
if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
return NULL;
}
return PyLong_FromLong(a + b);
}
Giải thích:
PyArg_ParseTuple(args, "ii", &a, &b)
: Giải mã tham số từ Python thành hai số nguyên.PyLong_FromLong(a + b)
: Chuyển kết quả về dạngPyObject*
để Python có thể hiểu.
Các dạng chữ ký hàm C trong extension
Các chữ ký của việc triển khai C cho các hàm của bạn luôn có một trong ba dạng sau:
static PyObject* MyFunction(PyObject *self, PyObject *args);
static PyObject* MyFunctionWithKeywords(PyObject *self, PyObject *args, PyObject *kw);
static PyObject* MyFunctionWithNoArgs(PyObject *self);
- Hàm có đối số (
MyFunction
): Nhận tham số từ Python quaargs
. - Hàm có cả đối số thường và đối số từ khóa (
MyFunctionWithKeywords
): Nhận tham số positional và keyword arguments từ Python. - Hàm không có đối số (
MyFunctionWithNoArgs
): Không nhận tham số nào từ Python.
Python không có hàm void
như trong C. Nếu hàm không cần trả về giá trị, em nên dùng Py_RETURN_NONE;
thay vì return Py_None;
để tránh rò rỉ bộ nhớ.
Định nghĩa bảng phương thức (Method Table)
Để Python có thể gọi các hàm C này, em cần đăng ký chúng trong một bảng phương thức (PyMethodDef
):
static PyMethodDef MyMethods[] = {
{"add", add, METH_VARARGS, "Cộng hai số nguyên"},
{NULL, NULL, 0, NULL}
};
Mỗi dòng trong bảng gồm:
"add"
: Tên hàm khi gọi từ Python.add
: Con trỏ đến hàm C.METH_VARARGS
: Kiểu tham số (ở đây là danh sách đối số)."Cộng hai số nguyên"
: Chuỗi mô tả hàm (Python dùnghelp(module.function)
để đọc mô tả này).
Hàm khởi tạo module
Cuối cùng, cần một hàm khởi tạo để Python nhận diện module:
static struct PyModuleDef mymodule = {
PyModuleDef_HEAD_INIT,
"mymodule",
"Module mở rộng viết bằng C",
-1,
MyMethods
};
PyMODINIT_FUNC PyInit_mymodule(void) {
return PyModule_Create(&mymodule);
}
"mymodule"
: Tên module khi import vào Python.MyMethods
: Danh sách các hàm trong module.
Sau khi biên dịch, module có thể được import vào Python như sau:
import mymodule
print(mymodule.add(3, 5)) # Kết quả: 8
Phương thức mapping table
Trong module mở rộng viết bằng C, mapping table được sử dụng để liên kết tên hàm Python với hàm C tương ứng. Đây là phần quan trọng giúp Python có thể gọi các hàm C trong extension.
Cấu trúc bảng ánh xạ phương thức
Bảng ánh xạ phương thức trong C được định nghĩa bằng struct PyMethodDef
, có dạng như sau:
static PyMethodDef ModuleMethods[] = {
{"function_name", function_pointer, method_flags, "Function description"},
{NULL, NULL, 0, NULL} // Kết thúc danh sách
};
Trong đó:
"function_name"
: Tên hàm khi gọi từ Python.function_pointer
: Con trỏ trỏ đến hàm C thực thi.method_flags
: Kiểu tham số hàm nhận."Function description"
: Chuỗi mô tả giúphelp(module.function_name)
hiển thị thông tin hàm.
Các kiểu method_flags
trong Python C API
METH_VARARGS
: Hàm nhận danh sách đối sốargs
.METH_KEYWORDS
: Hàm nhận cảargs
vàkwargs
.METH_NOARGS
: Hàm không nhận tham số.METH_O
: Hàm nhận một đối số duy nhất.METH_STATIC
vàMETH_CLASS
: Dùng trong class method.
Ví dụ bảng ánh xạ phương thức
Dưới đây là bảng ánh xạ cho một module có ba hàm:
add
: Cộng hai số nguyên.greet
: Trả về chuỗi chào.info
: In ra thông tin module.
#include <Python.h>
// Hàm C đơn giản
static PyObject* add(PyObject *self, PyObject *args) {
int a, b;
if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
return NULL;
}
return PyLong_FromLong(a + b);
}
// Hàm không có tham số
static PyObject* greet(PyObject *self) {
return PyUnicode_FromString("Xin chào từ C extension!");
}
// Hàm nhận một đối số duy nhất
static PyObject* info(PyObject *self, PyObject *arg) {
if (!PyUnicode_Check(arg)) {
PyErr_SetString(PyExc_TypeError, "Phải truyền một chuỗi.");
return NULL;
}
return PyUnicode_FromFormat("Thông tin: %S", arg);
}
// Bảng ánh xạ phương thức
static PyMethodDef MyMethods[] = {
{"add", add, METH_VARARGS, "Cộng hai số nguyên"},
{"greet", (PyCFunction)greet, METH_NOARGS, "Hàm không có tham số"},
{"info", info, METH_O, "Nhận một chuỗi và in thông tin"},
{NULL, NULL, 0, NULL} // Kết thúc danh sách
};
Tích hợp bảng phương thức vào module
Bảng phương thức cần được đăng ký trong struct PyModuleDef
:
static struct PyModuleDef mymodule = {
PyModuleDef_HEAD_INIT,
"mymodule",
"Module mở rộng viết bằng C",
-1,
MyMethods
};
PyMODINIT_FUNC PyInit_mymodule(void) {
return PyModule_Create(&mymodule);
}
Sau khi biên dịch, module có thể sử dụng trong Python như sau:
import mymodule
print(mymodule.add(3, 5)) # Output: 8
print(mymodule.greet()) # Output: Xin chào từ C extension!
print(mymodule.info("Extension Python")) # Output: Thông tin: Extension Python
Lưu ý
Luôn kết thúc bảng bằng
{NULL, NULL, 0, NULL}
để Python biết điểm dừng.Dùng đúng method_flags để tránh lỗi khi gọi hàm từ Python.
Mô tả đầy đủ các phương thức để hỗ trợ
help(module.function)
.
Bảng phương thức là một mảng các cấu trúc PyMethodDef
. Mỗi phần tử trong mảng này đại diện cho một phương thức trong module và được định nghĩa theo cấu trúc sau:
struct PyMethodDef {
char *ml_name; // Tên của hàm trong Python
PyCFunction ml_meth; // Con trỏ trỏ đến hàm C thực thi
int ml_flags; // Cờ xác định cách hàm nhận tham số
char *ml_doc; // Chuỗi mô tả hàm
};
Dưới đây là mô tả các thành viên của cấu trúc này:Dưới đây là mô tả chi tiết về các thành viên của PyMethodDef
:
ml_name
– Tên của hàm khi gọi từ Python.ml_meth
– Con trỏ trỏ đến hàm C xử lý logic của phương thức.ml_flags
– Xác định cách hàm nhận tham số, có thể là một trong các giá trị:METH_VARARGS
: Hàm nhận danh sách đối số.METH_KEYWORDS
: Hàm nhận cả args và kwargs.METH_NOARGS
: Hàm không có tham số.METH_O
: Hàm nhận một đối số duy nhất.
ml_doc
– Chuỗi mô tả giúphelp(module.function_name)
hiển thị thông tin chi tiết về hàm. Có thể đặtNULL
nếu không cần mô tả.
Ví dụ:
Bảng phương thức luôn cần kết thúc bằng một phần tử có giá trị NULL
để Python biết điểm dừng. Phần này sẽ giúp Python ánh xạ chính xác các hàm từ C sang Python, đảm bảo module mở rộng hoạt động đúng như mong đợi.
static PyMethodDef module_methods[] = {
{ "func", (PyCFunction)module_func, METH_NOARGS, "Mô tả hàm func" },
{ NULL, NULL, 0, NULL } // Kết thúc danh sách
};
Hàm khởi tạo module
Phần cuối cùng trong module mở rộng là hàm khởi tạo. Hàm này sẽ được trình thông dịch Python gọi khi module được tải vào chương trình. Theo quy tắc của Python C API, hàm khởi tạo phải được đặt tên theo mẫu PyInit_<ModuleName>
, trong đó <ModuleName>
là tên của module.
Hàm khởi tạo cần được xuất từ thư viện được biên dịch. Python định nghĩa PyMODINIT_FUNC
để đảm bảo hàm khởi tạo được xử lý đúng trên các môi trường biên dịch khác nhau. Khi viết hàm khởi tạo, chỉ cần sử dụng PyMODINIT_FUNC
để khai báo.
Dưới đây là cấu trúc tổng quát của hàm khởi tạo:
PyMODINIT_FUNC PyInit_ModuleName(void) {
return PyModule_Create(&module_definition);
}
Trong đó:
ModuleName
là tên module.module_definition
là cấu trúcPyModuleDef
chứa thông tin về module.
Ví dụ hoàn chỉnh
#include <Python.h>
// Định nghĩa hàm Python
static PyObject* helloworld(PyObject* self) {
return Py_BuildValue("s", "Hello, Python extensions!!");
}
// Chuỗi mô tả hàm
static char helloworld_docs[] = "helloworld(): Trả về chuỗi chào.\n";
// Bảng ánh xạ phương thức
static PyMethodDef helloworld_funcs[] = {
{"helloworld", (PyCFunction)helloworld, METH_NOARGS, helloworld_docs},
{NULL, NULL, 0, NULL} // Kết thúc danh sách
};
// Định nghĩa module
static struct PyModuleDef helloworld_module = {
PyModuleDef_HEAD_INIT,
"helloworld",
"Mô tả module extension",
-1,
helloworld_funcs
};
// Hàm khởi tạo module
PyMODINIT_FUNC PyInit_helloworld(void) {
return PyModule_Create(&helloworld_module);
}
Lưu ý
Không sử dụng
Py_InitModule3
, vì API này đã bị loại bỏ trong Python 3.Hàm khởi tạo phải có tiền tố
PyInit_
.PyModuleDef
là bắt buộc để định nghĩa module trong Python 3.
Xây dựng và cài đặt extension
Gói distutils
giúp phân phối module Python dễ dàng, bao gồm cả module thuần Python và module mở rộng. Các module này được phân phối dưới dạng mã nguồn, xây dựng và cài đặt thông qua script setup.py
.
Tạo file setup.py
Đối với module trên, bạn cần chuẩn bị script setup.py
như sau:
from distutils.core import setup, Extension
setup(name='helloworld', version='1.0', \
ext_modules=[Extension('helloworld', ['hello.c'])])
Cài đặt module
Bây giờ, sử dụng lệnh sau, lệnh này sẽ thực hiện tất cả các bước biên dịch và liên kết cần thiết, với các lệnh và cờ trình biên dịch và trình liên kết phù hợp, và sao chép thư viện động kết quả vào một thư mục thích hợp:
$ python setup.py install
Trên Unix, có thể cần quyền root:
sudo python setup.py install
Trên các hệ thống dựa trên Unix, bạn rất có thể cần phải chạy lệnh này với quyền root để có quyền ghi vào thư mục site-packages
. Điều này thường không phải là vấn đề trên Windows.
Import và sử dụng extension trong Python
Sau khi đã xây dựng và cài đặt extension thành công, bạn có thể import module đó vào script Python như một module thông thường. Ví dụ, với module helloworld
, bạn có thể sử dụng như sau:
import helloworld
# Gọi hàm đã định nghĩa trong extension
print(helloworld.helloworld())
Khi chạy đoạn mã trên, bạn sẽ thấy kết quả được hiển thị như bên dưới.
Hello, Python extensions!!
Điều này chứng tỏ extension đã được cài đặt đúng cách và có thể hoạt động như một module Python thông thường. Nếu gặp lỗi ModuleNotFoundError
, hãy kiểm tra lại quá trình cài đặt hoặc đảm bảo rằng module nằm trong thư mục có thể import được.
Truyền tham số vào function trong extension
Khi xây dựng extension trong Python, em có thể muốn định nghĩa các function chấp nhận tham số. Để làm được điều này, cần sử dụng một trong các chữ ký (signature) khác nhau cho function trong C. Ví dụ, một function nhận tham số sẽ được định nghĩa như sau:
static PyObject *module_func(PyObject *self, PyObject *args) {
/* Parse args and xử lý dữ liệu tại đây */
Py_RETURN_NONE;
}
Định nghĩa function với tham số
Để Python có thể gọi function này, cần khai báo nó trong bảng phương thức:
static PyMethodDef module_methods[] = {
{ "func", (PyCFunction)module_func, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL } // Kết thúc danh sách
};
Trong đó:
METH_VARARGS
cho phép function nhận nhiều tham số.NULL
ở cuối danh sách để đánh dấu kết thúc.
Trích xuất tham số bằng pyarg_parsetuple
Bạn có thể sử dụng hàm API PyArg_ParseTuple
để trích xuất các đối số từ con trỏ PyObject
duy nhất được truyền vào hàm C. Tham số đầu tiên của PyArg_ParseTuple
là args
, đối tượng chứa danh sách đối số cần phân tích. Tham số thứ hai là một chuỗi định dạng, dùng để mô tả cách các đối số được mong đợi. Mỗi đối số sẽ được biểu diễn bằng một hoặc nhiều ký tự trong chuỗi định dạng, cụ thể như sau:
static PyObject *module_func(PyObject *self, PyObject *args) {
int i;
double d;
char *s;
if (!PyArg_ParseTuple(args, "ids", &i, &d, &s)) {
return NULL;
}
/* Xử lý dữ liệu nhận được */
Py_RETURN_NONE;
}
"ids"
là chuỗi định dạng, trong đó:i
→int
(số nguyên)d
→double
(số thực)s
→char*
(chuỗi ký tự)
- Các tham số sau
"ids"
là địa chỉ của biến sẽ chứa dữ liệu sau khi phân tích.
Khi biên dịch phiên bản mới của module và nhập lại, bạn có thể gọi hàm mới với số lượng đối số tùy ý, thuộc bất kỳ kiểu dữ liệu nào.
module.func(1, s="three", d=2.0)
module.func(i=1, d=2.0, s="three")
module.func(s="three", d=2.0, i=1)
Danh sách định dạng PyArg_ParseTuple
Hàm PyArg_ParseTuple
được sử dụng để trích xuất tham số từ một tuple Python được truyền vào function C. Chữ ký của hàm như sau:
int PyArg_ParseTuple(PyObject *args, const char *format, ...);
- Trả về
0
nếu có lỗi, trả về giá trị khác0
nếu thành công. tuple
là tham số thứ hai của function C, chứa các đối số được truyền từ Python.format
là chuỗi mô tả kiểu dữ liệu của các tham số mong đợi.
Dưới đây là danh sách các mã định dạng cho hàm PyArg_ParseTuple
:
Mã | Kiểu dữ liệu C | Ý nghĩa |
---|---|---|
c | char | Chuỗi Python độ dài 1 → ký tự C. |
d | double | Float Python → double C. |
f | float | Float Python → float C. |
i | int | Integer Python → int C. |
l | long | Integer Python → long C. |
L | long long | Integer Python → long long C. |
O | PyObject* | Nhận một tham chiếu đến đối tượng Python. |
S | char* | Chuỗi Python không có null embedded → C char* . |
s# | char* + int | Chuỗi Python bất kỳ → địa chỉ + độ dài. |
t# | char* + int | Bộ đệm đơn phân đoạn (read-only). |
u | Py_UNICODE* | Chuỗi Unicode Python không nhúng null → C Py_UNICODE* . |
u# | Py_UNICODE* + int | Unicode Python → địa chỉ + độ dài. |
w# | char* + int | Bộ đệm đơn phân đoạn (read/write). |
z | char* | Giống s , nhưng chấp nhận None (trả về NULL ). |
z# | char* + int | Giống s# , nhưng chấp nhận None . |
(...) | Phụ thuộc nội dung | Tuple Python được xem như các đối số riêng lẻ. |
` | ` | – |
: | – | Kết thúc định dạng, tiếp theo là tên function (cho thông báo lỗi). |
; | – | Kết thúc định dạng, tiếp theo là toàn bộ thông báo lỗi. |
Sử dụng PyArg_ParseTuple
để xử lý tham số
Hàm Py_BuildValue
nhận một chuỗi định dạng tương tự như PyArg_ParseTuple
. Tuy nhiên, thay vì truyền địa chỉ của các biến để lưu giá trị, bạn sẽ truyền trực tiếp các giá trị thực tế cần tạo. Dưới đây là ví dụ triển khai một hàm add
trong C, tương đương với một function trong Python:
Triển khai trong C
static PyObject *foo_add(PyObject *self, PyObject *args) {
int a, b;
if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
return NULL;
}
return Py_BuildValue("i", a + b);
}
Tương đương trong Python
def add(a, b):
return a + b
Bạn cũng có thể trả về nhiều giá trị từ hàm C bằng cách sử dụng Py_BuildValue
. Ví dụ, hàm dưới đây trả về cả tổng và hiệu của hai số:
Triển khai trong C
static PyObject *foo_add_subtract(PyObject *self, PyObject *args) {
int a, b;
if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
return NULL;
}
return Py_BuildValue("ii", a + b, a - b);
}
Tương đương trong Python
def add_subtract(a, b):
return a + b, a - b
Bằng cách sử dụng PyArg_ParseTuple
và Py_BuildValue
, bạn có thể dễ dàng giao tiếp giữa Python và C, giúp module mở rộng hoạt động mượt mà hơn.
Hàm Py_BuildValue – Trả về giá trị từ extension
Hàm Py_BuildValue
giúp tạo các đối tượng Python từ các giá trị trong C và trả về dưới dạng PyObject*
. Chữ ký của hàm như sau:
PyObject* Py_BuildValue(char* format,...)
format
là một chuỗi mô tả kiểu dữ liệu của đối tượng Python cần xây dựng.- Các tham số tiếp theo là giá trị C tương ứng.
- Giá trị trả về là một tham chiếu mới đến đối tượng Python được tạo.
Bảng mã định dạng thường dùng
Code | C type | Ý nghĩa |
c | char | Chuyển một ký tự C thành chuỗi Python có độ dài 1. |
d | double | Chuyển double trong C thành số float trong Python. |
f | float | Chuyển float trong C thành số float trong Python. |
i | int | Chuyển int trong C thành số int trong Python. |
l | long | Chuyển long trong C thành số int trong Python. |
N | PyObject* | Trả về một đối tượng Python mà không tăng reference count. |
O | PyObject* | Trả về một đối tượng Python và tăng reference count (INCREF ). |
O& | convert+void* | Chuyển đổi tùy chỉnh. |
s | char* | Chuyển chuỗi C (char* kết thúc bằng \0 ) thành chuỗi Python. Nếu NULL , trả về None . |
s# | char*+int | Chuyển chuỗi C có độ dài cụ thể thành chuỗi Python. Nếu NULL , trả về None . |
u | Py_UNICODE* | Chuyển wchar_t* kết thúc bằng \0 trong C thành chuỗi Unicode Python. Nếu NULL , trả về None . |
u# | Py_UNICODE*+int | Chuyển wchar_t* với độ dài cụ thể thành chuỗi Unicode Python. Nếu NULL , trả về None . |
w# | char*+int | Chuyển bộ đệm có thể đọc/ghi thành tuple chứa địa chỉ và độ dài. |
z | char* | Giống s , nhưng chấp nhận None (char* trong C có thể là NULL ). |
z# | char*+int | Giống s# , nhưng chấp nhận None . |
(…) | as per … | Tạo tuple Python từ các giá trị C. |
[…] | as per … | Tạo danh sách Python từ các giá trị C. |
{…} | as per … | Tạo từ điển Python từ các cặp khóa-giá trị trong C. |
Ví dụ:
PyObject *dict = Py_BuildValue("{issi}", 23, "zig", "zag", 42);
// Tương đương với Python: {23: "zig", "zag": 42}
Hàm Py_BuildValue
giúp dễ dàng tạo các kiểu dữ liệu Python từ C, hỗ trợ tốt cho việc viết extension module.
Vietnix – Nhà cung cấp dịch vụ lưu trữ uy tín, tốc độ và bảo mật hàng đầu
Vietnix là một trong những đơn vị cung cấp dịch vụ cho thuê máy chủ (server), hosting, VPS và tên miền (domain) hàng đầu tại Việt Nam. Với mục tiêu mang đến giải pháp lưu trữ hiệu quả và bảo mật tối ưu, Vietnix cam kết cung cấp dịch vụ chất lượng vượt trội cùng đội ngũ hỗ trợ kỹ thuật chuyên nghiệp, sẵn sàng hỗ trợ 24/7. Hơn 80.000 khách hàng đã lựa chọn Vietnix nhờ vào dịch vụ cho thuê máy chủ đáng tin cậy, giúp tối ưu hóa hiệu suất và bảo mật dữ liệu cho doanh nghiệp.
Thông tin liên hệ:
- Hotline: 18001093
- Email: sales@vietnix.com.vn
- Địa chỉ: 265 Hồng Lạc, Phường 10, Quận Tân Bình, Thành Phố Hồ Chí Minh.
- Website: https://vietnix.vn/
Câu hỏi thường gặp
Làm sao để sử dụng Python C API để tạo một mô-đun với nhiều hàm, và làm thế nào để kết hợp chúng trong một extension duy nhất?
Việc tạo một mô-đun với nhiều hàm trong extension Python bao gồm việc định nghĩa từng hàm riêng biệt và khai báo một danh sách các hàm trong cấu trúc PyMethodDef
để nhóm chúng lại với nhau.
Tại sao cần phải biên dịch lại mỗi lần chỉnh sửa extension trong Python và có cách nào để giảm bớt việc này không?
Việc biên dịch lại mỗi lần chỉnh sửa là cần thiết vì Python không tự động nhận diện thay đổi trong mã C. Tuy nhiên, có thể sử dụng công cụ như Cython
hoặc các kỹ thuật tối ưu hóa biên dịch để giảm thời gian xây dựng lại mô-đun.
Có phải tất cả extension Python đều cần phải sử dụng Python C API, hay có thể dùng cách khác?
Không, ngoài Python C API, bạn còn có thể sử dụng các công cụ như Cython
hoặc PyPy
để tạo extension mà không phải làm việc trực tiếp với mã C.
Python C API và Cython có điểm gì khác biệt khi tạo extension?
Python C API yêu cầu lập trình viên làm việc trực tiếp với mã C, trong khi Cython là một công cụ giúp viết extension Python mà không cần phải hiểu sâu về C.
Có thể sử dụng extension Python cho các tác vụ xử lý dữ liệu lớn như học máy hoặc phân tích dữ liệu không?
Có thể, extension Python có thể được sử dụng để tối ưu hóa các tác vụ tính toán nặng, chẳng hạn như học máy hoặc phân tích dữ liệu, giúp cải thiện hiệu suất khi làm việc với dữ liệu lớn.
Lời kết
Hy vọng qua bài viết này, bạn đã hiểu rõ hơn về cách làm việc với Extension trong Python và những lợi ích mà chúng mang lại. Việc tích hợp mã C/C++ giúp mở rộng hiệu suất cho các ứng dụng Python của bạn một cách đáng kể. Nếu bạn có bất cứ thắc mắc hay cần hỗ trợ gì, hãy để lại bình luận bên dưới, mình sẽ hỗ trợ nhanh nhất có thể. Cảm ơn bạn đã đọc!
Mọi người cũng xem: