Python C api - 函数重载
Python C api - function overloading
我有许多接受不同参数的 C 函数,例如
foo_i(int a)
foo_c(char c)
是否可以在 python C api 中重载这些函数?
我尝试使用以下方法table:
static PyMethodDef test_methods[] = {
{"foo", (PyCFunction)foo_i, METH_VARARGS, "int"},
{"foo", (PyCFunction)foo_c, METH_VARARGS, "char"},
{NULL, NULL, 0, NULL}
};
但是当我从 python 调用 foo 时,我总是最终使用 table.
底部的函数
关于如何调用 foo_i() 和 foo_c() 的任何想法 foo() 在 python C-api?
谢谢!
要么给它们不同的 Python 级别名称,要么编写一个包装函数,对提供的参数进行类型检查并分派到正确的 "real" 函数。 Python 本身不直接支持基于参数类型的重载函数。
如果您想要为您编写包装器,您可以看看 pybind11
,它确实允许在您尝试的意义上进行重载(它通过引擎盖下的类型检查包装器实现,所以这只是语法糖,而不是行为上的改变。
未经测试的示例代码:
static PyObject*
foo_wrapper(PyObject *self, PyObject *arg)
{
Py_buffer view;
Py_ssize_t ival;
// Check for/handle length 1 bytes-like object (bytes, bytearray, small mmap, etc.)
if (PyObject_GetBuffer(arg, &view, PyBUF_SIMPLE) == 0) {
if (view.len != 1) {
PyErr_Format(PyExc_ValueError, "Must receive exactly one byte, got %zd", view.len);
PyBuffer_Release(&view);
return NULL;
}
foo_c(((char*)view.buf)[0]);
Py_RETURN_NONE; // Or convert return from foo_c if it exists
}
// Check for/handle integer-like object that fits in C int
PyErr_Clear(); // Ignore error for objects not supporting buffer protocol
ival = PyNumber_AsSsize_t(arg, PyExc_ValueError);
if (PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
// Replace with general error message about both accepted argument types,
// since only reporting error from int conversion might confuse folks
PyErr_Format(PyExc_TypeError, "Argument must be length 1 bytes-like object or integer; received %R", Py_TYPE(arg));
}
return NULL;
}
// Check valid range (Py_ssize_t often larger than int)
if (ival < INT_MIN or ival > INT_MAX) {
return PyErr_Format(PyExc_ValueError, "Integer must be in range [%d-%d]; received %zd", INT_MIN, INT_MAX, ival);
}
foo_i((int)ival);
Py_RETURN_NONE; // Or convert return from foo_i if it exists
}
static PyMethodDef test_methods[] = {
{"foo", (PyCFunction)foo_wrapper, METH_O, "Wrapper for foo_c and foo_i"},
{NULL, NULL, 0, NULL}
};
我有许多接受不同参数的 C 函数,例如
foo_i(int a)
foo_c(char c)
是否可以在 python C api 中重载这些函数?
我尝试使用以下方法table:
static PyMethodDef test_methods[] = {
{"foo", (PyCFunction)foo_i, METH_VARARGS, "int"},
{"foo", (PyCFunction)foo_c, METH_VARARGS, "char"},
{NULL, NULL, 0, NULL}
};
但是当我从 python 调用 foo 时,我总是最终使用 table.
底部的函数关于如何调用 foo_i() 和 foo_c() 的任何想法 foo() 在 python C-api?
谢谢!
要么给它们不同的 Python 级别名称,要么编写一个包装函数,对提供的参数进行类型检查并分派到正确的 "real" 函数。 Python 本身不直接支持基于参数类型的重载函数。
如果您想要为您编写包装器,您可以看看 pybind11
,它确实允许在您尝试的意义上进行重载(它通过引擎盖下的类型检查包装器实现,所以这只是语法糖,而不是行为上的改变。
未经测试的示例代码:
static PyObject*
foo_wrapper(PyObject *self, PyObject *arg)
{
Py_buffer view;
Py_ssize_t ival;
// Check for/handle length 1 bytes-like object (bytes, bytearray, small mmap, etc.)
if (PyObject_GetBuffer(arg, &view, PyBUF_SIMPLE) == 0) {
if (view.len != 1) {
PyErr_Format(PyExc_ValueError, "Must receive exactly one byte, got %zd", view.len);
PyBuffer_Release(&view);
return NULL;
}
foo_c(((char*)view.buf)[0]);
Py_RETURN_NONE; // Or convert return from foo_c if it exists
}
// Check for/handle integer-like object that fits in C int
PyErr_Clear(); // Ignore error for objects not supporting buffer protocol
ival = PyNumber_AsSsize_t(arg, PyExc_ValueError);
if (PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
// Replace with general error message about both accepted argument types,
// since only reporting error from int conversion might confuse folks
PyErr_Format(PyExc_TypeError, "Argument must be length 1 bytes-like object or integer; received %R", Py_TYPE(arg));
}
return NULL;
}
// Check valid range (Py_ssize_t often larger than int)
if (ival < INT_MIN or ival > INT_MAX) {
return PyErr_Format(PyExc_ValueError, "Integer must be in range [%d-%d]; received %zd", INT_MIN, INT_MAX, ival);
}
foo_i((int)ival);
Py_RETURN_NONE; // Or convert return from foo_i if it exists
}
static PyMethodDef test_methods[] = {
{"foo", (PyCFunction)foo_wrapper, METH_O, "Wrapper for foo_c and foo_i"},
{NULL, NULL, 0, NULL}
};