Python C API-函数重载 [英] Python C api - function overloading
问题描述
我有许多C函数接受不同的参数,例如
I have a number of C functions that accept different arguments, e.g.
foo_i(int a)
foo_c(char c)
是否可以在python C api中重载这些功能?
Is it possible to overload these functions in python C api?
我尝试使用以下方法表:
I tried to use the following methods 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 时,我总是最终使用表底部的函数.
But when I invoke foo from python I always end up using the function at the bottom of the table.
关于如何在python C-api中使用 foo()调用 foo_i()和 foo_c()的任何想法?
Any ideas on how to invoke both foo_i() and foo_c() using foo() in python C-api?
谢谢!
推荐答案
要么给他们提供不同的Python级别名称,要么编写一个包装函数,该函数对类型进行检查,然后将其分发给正确的真实"函数. Python本身不直接支持基于参数类型的重载函数.
Either give them different Python level names, or write a single wrapper function that type checks the argument provided and dispatches to the correct "real" function. Python itself has no direct support for overloading functions based on argument types.
如果要为您编写包装器,可以看一下pybind11
,它确实允许您尝试执行的重载(它是通过内部检查类型的包装器实现的,因此只是语法上的糖,而不是改变行为.)
If you want the wrapper written for you, you might take a look at pybind11
, which does allow overloading in the sense you're attempting (it does so via a type checking wrapper under the hood, so it's just syntactic sugar, not a change in behavior).
未经测试的示例代码:
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}
};
这篇关于Python C API-函数重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!