Cython эквивалент c определяет #define myfunc (узел x, …) SetNode (x.getattributeNode (), __ VA_ARGS__)

Китонный эквивалент c определяет

#define myfunc(Node x,...) SetNode(x.getattributeNode(),__VA_ARGS__) 

У меня есть AC Api SetNode, который принимает первый аргумент узел узла типа структуры и N переменных (N – это переменное число от 0-N)

здесь приводится пример решения такой проблемы

exampleAPI.c

 #include float sumN(int len,...){ va_list argp; int i; float s=0; va_start(argp,len); for(i=0;i<len;i++){ s+=va_arg(argp,int); } va_end(argp); } 

exampleAPI.h

 #include float sumN(int len,...) 

examplecode.c

 #include #include"exampleAPI.h" int len(float first,...){ va_list argp; int i=1; va_start(argp,first); while(1){ if(va_arg(argp,float)==NULL){ return i } else{ i++; } } va_end(argp); } #define sum(...) sumN(len(__VA_ARGS__),__VA_ARGS__) в #include #include"exampleAPI.h" int len(float first,...){ va_list argp; int i=1; va_start(argp,first); while(1){ if(va_arg(argp,float)==NULL){ return i } else{ i++; } } va_end(argp); } #define sum(...) sumN(len(__VA_ARGS__),__VA_ARGS__) 

Теперь вызов

 sum(1,2,3,4); 

вернется 10.000000

 sum(1.5,6.5); 

вернется 8.00000

Мне нужна альтернатива cython для определения bellow c, а не выше, потому что у меня есть C-API, у которого есть функция SetNode, которая принимает переменное количество аргументов, и я хочу обернуть ее в cython и вызвать из python

  #define myfunc(Node x,...) SetNode(x.getattributeNode(),__VA_ARGS__) 

здесь Node – это class, определенный в cython, который содержит ac stuct как атрибут, а getattributeNode () – это функция classа Node, которая возвращает c struct, которая должна быть передана в C-API.

 cdef extern "Network.h": ctypedef struct node_bn: pass node_bn* SetNode(node_bn* node,...) cdef class Node: cdef node_bn *node cdef getattributeNode(self): return self.node def setNode(self,*arg): self.node=SetNode(self.node,*arg) # Error cannot convert python objects to c type 

Альтернативная вещь, которую я пробовал

 cdef extern from "stdarg.h": ctypedef struct va_list: pass ctypedef struct fake_type: pass void va_start(va_list, void* arg) void* va_arg(va_list, fake_type) void va_end(va_list) fake_type int_type "int" cdef extern "Network.h": ctypedef struct node_bn: pass node_bn* VSetNode(node_bn* node,va_list argp) cdef class Node: cdef node_bn *node cdef getattributeNode(self): return self.node cpdef _setNode(self,node_bn *node,...): cdef va_list agrp va_start(va_list, node) self.node=VSetNode(node,argp) va_end(va_list) def setNode(self,*arg): self._setNode(self.node,*arg) 

отлично работает, когда список аргументов пуст

 n = Node() n.setNode() #This works n.SetNode("top",1) # error takes exactly one argument given 3 in self._setNode(self.node,*arg) 

Если кто-то может предложить эквивалент цитона, это было бы здорово.

Я не думаю, что это легко сделать, хотя Cython (проблема говорит Cython о том, какие преобразования типов нужно делать для произвольного количества аргументов). Лучшее, что я могу предложить, это использовать стандартную библиотеку ctypes библиотеки для этого конкретного случая и обернуть остальные в Cython.

Для примера я использовал очень простую функцию sum. va_sum.h содержит:

 typedef struct { double val; } node_bn; node_bn* sum_va(node_bn* node,int len, ...); /* on windows this must be: __declspec(dllexport) node_bn* sum_va(node_bn* node,int len, ...); */ 

и va_sum.c содержит:

 #include  #include "va_sum.h" node_bn* sum_va(node_bn* node,int len, ...) { int i; va_list vl; va_start(vl,len); for (i=0; ival += va_arg(vl,double); } va_end(vl); return node; } 

Я написал это, поэтому он добавляет все в поле в структуре, чтобы продемонстрировать, что вы можете без проблем переходить с указателями на структуры.

Файл Cython:

 # definition of a structure cdef extern from "va_sum.h": ctypedef struct node_bn: double val; # obviously you'll want to wrap things in terms of Python accessible classes, but this atleast demonstrates how it works def test_sum(*args): cdef node_bn input_node; cdef node_bn* output_node_p; input_node.val = 5.0 # create a node, and set an initial value from ctypes import CDLL, c_double,c_void_p import os.path # load the Cython library with ctypes to gain access to the "sum_va" function # Assuming you've linked it in when you build the Cython module full_path = os.path.realpath(__file__) this_file_library = CDLL(full_path) # I treat all my arguments as doubles - you may need to do # something more sophisticated, but the idea is the same: # convert them to the c-type the function is expecting args = [ c_double(arg) for arg in args ] sum_va = this_file_library.sum_va sum_va.restype = c_void_p # it returns a pointer # pass the pointers as a void pointer # my c compiler warns me if I used int instead of long # but which integer type you have to use is likely system dependent # and somewhere you have to be careful output_node_p_as_integer = sum_va(c_void_p(&input_node),len(args), *args) # unfortunately getting the output needs a two stage typecast - first to a long, then to a pointer output_node_p = ((output_node_p_as_integer)) return output_node_p.val 

Вам необходимо скомпилировать va_sum.c вместе с вашим файлом Cython (например, adding sources = ['cython_file.pyx','va_sum.c'] в setup.py adding sources = ['cython_file.pyx','va_sum.c']

Ctypes, вероятно, немного медленнее, чем Cython (я думаю, что на каждом вызове есть разумные накладные расходы), и странно смешивать их, но это должно по крайней мере позволить вам написать основную оболочку в Cython и использовать ctypes, чтобы обойти конкретное ограничение ,

Вероятно, это не правильный ответ, так как я не уверен, что полностью понимаю этот вопрос. Я бы ответил в комментарии, но форматирование кода слишком плохое. В Python доступны функции sum и len :

 def my_len(*args): return len(args) def my_sum(*args): return sum(args) print "len =", my_len("hello", 123, "there") print "sum =", my_sum(6.5, 1.5, 2.0) 

выходы:

 len = 3 sum = 10.0