2016-10-04 21 views
9

C içinde, float veya int türünün girişlerini alabilen Python'u genişleten bir işlev oluşturmak istiyorum. Yani temel olarak kabul edilebilir girişler olmak için f(5) ve f(5.5)'u istiyorum.Bir int veya float gerektiren bir C işlevi nasıl yazabilirim?

if (!PyArg_ParseTuple(args, "i", $value)) numaralı telefonu kullanabileceğimi sanmıyorum çünkü yalnızca int ya da yalnızca yüzer.

İşlevlerimi, ints veya float olan girişlere nasıl izin verebilirim?

Sadece girdiyi alıp bir PyObject'e yerleştirmem ve PyObject'in türünü almam gerekip gerekmediğini merak ediyorum - bu doğru yaklaşım mı?

+0

Not: Okumayı kolaylaştırmak için sorunuzu düzenledim. Eğer değiştirdiğim bir şeyden hoşlanmıyorsanız, o zaman onu değiştirmek için çekinmeyin, çünkü bu sizin sorunuz değil. – immibis

+1

Muhtemelen PyObject ile çalışmak ve daha sonra sayılarla çalışmak için [Numara Protokolü] (https://docs.python.org/2/c-api/number.html) kullanmak istiyorsunuz. Örneğin, bir "float" a zorlamak için _need_ 'i kurarsanız, PyObject'inizde 'PyNumber_Float' öğesini çağırabilirsiniz. – mgilson

cevap

5

Eğer floatları kabul etmek için bir C işlevi bildirirseniz, derleyici bir int iletirseniz şikayet etmez.

#include <stdio.h> 

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

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

Bir piton modülü sürümünü 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]) 

Bir örnek:

Örneğin, bu program cevabı 2,000000 üretir
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

Ancak C derleyicisi yalnızca 'int' bir' float '* işlevini çağırmadan * dönüştürdüğü için. –

+0

Bu bir problem mi? –

+0

Python çalışma zamanının aynı şeyi yapacağını düşünmüyorum. –

1

Böyle giriş değerinin türünü kontrol edebilirsiniz: Sen kullanarak nesneden şamandıra değer elde edebilirsiniz

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); 

Ama bu özel durumda muhtemelen gerek bunu yapmak için hiçbir neyi ayrıştırdığınızı veya şamandıra aldığınız şeyi bir float olarak yakalayabilir ve yuvarlaklığı kontrol edebilirsiniz:

float target; 
    if (!PyArg_ParseTuple(args, "f", &target)) { 
       PyErr_SetString(PyExc_TypeError, "Nope."); 
       return NULL; 
    } 

    if (target - (int)target) { 
     printf("\n input is float \n"); 
    } 
    else { 
     printf("\n input is int \n"); 
    } 
1

Şamandıralar (genellikle) üzerinden geçilir Ints, yazma sırasında (genellikle) yığın yoluyla iletilir. Bu, kelimenin tam anlamıyla, fonksiyonun içinde, argümanın bir float veya int olduğunu kontrol edemediğiniz anlamına gelir.

Tek çözüm, türü int veya double (float değil) olarak belirten ilk argüman ile, variadic arguments kullanmaktır.

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 
} 

Ancak, python'un çağıran değişken işlevlerini ele alıp alamayacağı konusunda emin değilim, bu yüzden YMMV. Son hendek çabası olarak, değeri her zaman bir arabelleğe aktarabilir ve işlevinizi sscanf float/int arabellekten sağlayabilirsiniz.