Python C API-函数重载 [英] Python C api - function overloading

查看:129
本文介绍了Python C API-函数重载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有许多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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆