2016-10-04 6 views
9

float 또는 int 유형의 입력을받을 수있는 Python을 확장하는 C로 함수를 만들고 싶습니다. 기본적으로 f(5)f(5.5)을 허용 입력으로 사용합니다.int 또는 float 중 하나를 취하는 C 함수를 작성하려면 어떻게해야합니까?

if (!PyArg_ParseTuple(args, "i", $value))은 int 또는 float 만 사용하기 때문에 사용할 수 없다고 생각합니다.

int 또는 float 입력을 허용하려면 어떻게합니까?

입력을 받아서 PyObject에 넣고 어떻게 든 PyObject 유형을 가져 오는지 궁금합니다. 올바른 접근 방식입니까?

+0

참고 : 쉽게 읽을 수 있도록 질문을 편집했습니다. 당신이 내가 바꾼 것을 좋아하지 않는다면, 당신의 질문이 내 것이 아니기 때문에 그것을 자유롭게 되돌릴 수 있습니다. – immibis

+1

아마도'PyObject'로 작업하고 숫자로 작업하기 위해 [Number Protocol] (https://docs.python.org/2/c-api/number.html)을 사용하고 싶을 것입니다. 예를 들어,'float'을 강요 할 필요가 있다면'PyObject'에서'PyNumber_Float'를 호출 할 수 있습니다. – mgilson

답변

5

C 함수가 부동을 허용하도록 선언하면 컴파일러는 int를 건네 주면 불평하지 않습니다.

#include <stdio.h> 

float f(float x) { 
    return x+1; 
} 

int main() { 
    int i=1; 
    printf ("%f", f(i)); 
} 

파이썬 모듈 버전 iorf.c :

#include <Python.h> 

static PyObject *IorFError; 

float f(float x) { 
    return x+1; 
} 


static PyObject * 
fwrap(PyObject *self, PyObject *args) { 
    float in=0.0; 
    if (!PyArg_ParseTuple(args, "f", &in)) 
    return NULL; 
    return Py_BuildValue("f", f(in)); 
} 

static PyMethodDef IorFMethods[] = { 
    {"fup", fwrap, METH_VARARGS, 
    "Arg + 1"}, 
    {NULL, NULL, 0, NULL}  /* Sentinel */ 
}; 


PyMODINIT_FUNC 
initiorf(void) 
{ 
    PyObject *m; 

    m = Py_InitModule("iorf", IorFMethods); 
    if (m == NULL) 
    return; 

    IorFError = PyErr_NewException("iorf.error", NULL, NULL); 
    Py_INCREF(IorFError); 
    PyModule_AddObject(m, "error", IorFError); 
} 

setup.py :

from distutils.core import setup, Extension 

module1 = Extension('iorf', 
        sources = ['iorf.c']) 

setup (name = 'iorf', 
     version = '0.1', 
     description = 'This is a test package', 
     ext_modules = [module1]) 

예 :

예를 들어,이 프로그램은 응답 2.000000 생산
03:21 $ python 
Python 2.7.10 (default, Jul 30 2016, 18:31:42) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import iorf 
>>> print iorf.fup(2) 
3.0 
>>> print iorf.fup(2.5) 
3.5 
+0

하지만 C 컴파일러가 함수를 호출하기 전에'int'를'float' *로 변환했기 때문에. –

+0

그게 문제가 되나요? –

+0

파이썬 런타임이 똑같이 할 것이라고 생각하지 않습니다. –

1

이 같은 입력 값의 유형을 확인할 수 있습니다 당신은 사용하여 객체로부터 float 값을 추출 할 수 있습니다

PyObject* check_type(PyObject*self, PyObject*args) { 
    PyObject*any; 

    if (!PyArg_ParseTuple(args, "O", &any)) { 
     PyErr_SetString(PyExc_TypeError, "Nope."); 
     return NULL; 
    } 

    if (PyFloat_Check(any)) { 
     printf("indeed float"); 
    } 
    else { 
     printf("\nint\n"); 
    } 

    Py_INCREF(Py_None); 

    return Py_None; 
} 

:

double result=PyFloat_AsDouble(any); 

그러나이 특정 상황에서 아마 필요가이 작업을 수행하지 않으려면 없음 int로 파싱하거나 플로트로 플로트로 잡고 둥글기를 검사 할 수 있습니다.

1

플로트는 (일반적으로) 경유로 int가 (일반적으로) 스택을 통해 전달되는 동안 레지스터. 즉, 함수 내부에서 말 그대로 인수가 float인지 int인지 여부를 확인할 수 없습니다.

유일하게 해결할 수있는 방법은 variadic 인수를 사용하는 것입니다. 첫 번째 인수는 int 또는 double (부동 상태가 아님)으로 형식을 지정합니다.

func_int_or_double (uint8_t type, ...) { 
va_list ap; 
va_start (ap, type); 
int intarg; 
double doublearg; 
if (type==1) { 
    intarg = va_arg (ap, int); 
} 
if (type==2) { 
    doublearg = va_arg (ap, double); 
} 
va_end (ap); 
// Your code goes here 
} 

비록 파이썬이 가변적 인 함수를 호출 할 수 있는지 잘 모르겠지만, YMMV. 마지막 도랑 노력으로 버퍼에 값을 sprintf 할 수 있으며 함수 sscanf가 버퍼에서 float/int가되도록 할 수 있습니다.