首页 > 解决方案 > 处理 Ctypes 中的默认参数

问题描述

试图在下面包装一个像这样的函数。

int foo(int x=1)
{
   x++;
   return x;
}

如何使用 argtypes 处理默认参数?

标签: pythonctypes

解决方案


有一种技术ctypes可以声明默认参数和输出参数,但是您必须以不同的方式实例化函数。

这是一个用于包装和制作 pythonic 的 C++ 函数:

#define API __declspec(dllexport)

extern "C" {
    API int test(double first, double second, double* out) {
        if(second == 0)
            return 1; // error code for divide by zero
        *out = first / second;
        return 0;
    }
}

测试.py:

from ctypes import *

dll = CDLL('./test')

INPUT = 1   # constants for paramflags below
OUTPUT = 2

# Sample function returns an error code,
# This function checks it and raises an exception instead.
def errcheck(result,func,args):
    if result:
        raise ZeroDivisionError()
    return args


PROTOTYPE = CFUNCTYPE(c_int,c_double,c_double,POINTER(c_double))

# First parameter is a tuple of function name and dll reference.
# Second parameter is a tuple-of-tuples, the same length as number of arguments(3).
# The tuples are (type,name,default).  Name and default are optional.
# names allow calling the function with named parameters.
# Output-only arguments (if any) are return as the result, as tuple if necessary.
# The normal return value is lost unless captured with errcheck.
test = PROTOTYPE(('test',dll),((INPUT,'first',5),(INPUT,'second',2),(OUTPUT,)))
test.errcheck = errcheck

print(test())                  # 5 / 2 = 2.5
print(test(8))                 # 8 / 2 = 4.0
print(test(second=5,first=10)) # 10 / 5 = 2.0
print(test(second=0))          # 5 / 0 ... exception!

输出:

2.5
4.0
2.0
Traceback (most recent call last):
  File "C:\test.py", line 20, in <module>
    result = test(second=0)
  File "C:\test.py", line 7, in errcheck
    raise ZeroDivisionError()
ZeroDivisionError

如果这看起来很复杂,包装函数也可以:

from ctypes import *

# Sample function returns an error code,
# This function checks it and raises an exception instead.
def errcheck(result,func,args):
    if result:
        raise ZeroDivisionError()
    return args

dll = CDLL('./test')
dll.test.argtypes = c_double,c_double,POINTER(c_double)
dll.test.restype = c_int
dll.test.errcheck = errcheck

def test(first=5,second=2):
    out = c_double()
    dll.test(first,second,byref(out))
    return out.value

print(test())                  # 5 / 2 = 2.5
print(test(8))                 # 8 / 2 = 4.0
print(test(second=5,first=10)) # 10 / 5 = 2.0
print(test(second=0))          # 5 / 0 ... exception!

(相同的输出)


推荐阅读