2011-11-29 9 views
10

Encontré una situación con python puro y el módulo C python. Para resumir, ¿cómo puedo aceptar y manipular el objeto python en el módulo C? Mi parte de python se verá así.Pasando un objeto al módulo C, en Python


    #!/usr/bin/env python 

    import os, sys 
    from c_hello import * 

    class Hello: 
     busyHello = _sayhello_obj 

    class Man: 
     def __init__(self, name): 
      self.name = name 
     def getName(self): 
      return self.name 

    h = Hello() 
    h.busyHello(Man("John")) 

en C, hay dos cosas que deben resolverse. primero, ¿cómo puedo recibir el objeto? segundo, ¿cómo puedo llamar un método desde el objeto?


    static PyObject * 
    _sayhello_obj(PyObject *self, PyObject *args) 
    { 
     PyObject *obj; 
     // How can I fill obj? 

     char s[1024]; 
     // How can I fill s, from obj.getName() ? 

     printf("Hello, %s\n", s); 
     return Py_None; 
    } 
+0

Espera, ¿qué estás pasando en '_sayhello_obj'? ¿Es 'obj' (presumiblemente,' Hombre ("Juan") ')? O 'obj.getName()'? ¿O es 'obj' en la función C realmente' obj.getName() 'de la llamada de Python? – detly

+0

Me disculpo. Tenía sueño cuando hice esta pregunta. obj era lo que quería pasar. obj.getName() fue copiado accidentalmente de mi experimento. Actualicé la pregunta. – Raymond

+0

Bueno, porque esa es la pregunta que respondí! Lo sospechaba de todos modos. – detly

Respuesta

10

Para extraer un argumento de una invocación del método, es necesario mirar las funciones documentadas en Parsing arguments and building values, como PyArg_ParseTuple. (Eso es por si solo está tomando argumentos posicionales! Hay otros para argumentos posicionales y de palabras clave, etc.)

El objeto que obtiene de PyArg_ParseTuple no tiene un recuento de referencias incrementado. Para funciones C simples, probablemente no tenga que preocuparse por esto. Si está interactuando con otras funciones de Python/C, o si está liberando el bloqueo de intérprete global (es decir, permitiendo el enhebrado), debe pensar detenidamente sobre la propiedad del objeto.

static PyObject * 
_sayhello_obj(PyObject *self, PyObject *args) 
{ 
    PyObject *obj = NULL; 
    // How can I fill obj? 

    static char fmt_string = "O" // For "object" 

    int parse_result = PyArg_ParseTuple(args, fmt_string, &obj); 

    if(!parse_res) 
    { 
    // Don't worry about using PyErr_SetString, all the exception stuff should be 
    // done in PyArg_ParseTuple() 
    return NULL; 
    } 

    // Of course, at this point you need to do your own verification of whatever 
    // constraints might be on your argument. 

Para llamar a un método en un objeto, es necesario utilizar ya sea PyObject_CallMethod o PyObject_CallMethodObjArgs, dependiendo de cómo se construye la lista de argumentos y el nombre del método. ¡Y vea mi comentario en el código sobre la propiedad de objetos!

Desplazamiento rápido solo para asegurarse de que no se está preparando para una caída posterior: si realmente está obteniendo el hilo para imprimirlo, será mejor que obtenga la referencia del objeto y lo pase al PyObject_Print . Por supuesto, tal vez esto es sólo para la ilustración, o si conoce mejor que yo lo que quiere hacer con los datos;)

char s[1024]; 
    // How can I fill s, from obj.getName() ? 

    // Name of the method 
    static char method_name = "getName"; 
    // No arguments? Score! We just need NULL here 
    char method_fmt_string = NULL; 

    PyObject *objname = PyObject_CallMethod(obj, obj_method, method_fmt_string); 
    // This is really important! What we have here now is a Python object with a newly 
    // incremented reference count! This means you own it, and are responsible for 
    // decrementing the ref count when you're done. See below. 

    // If there's a failure, we'll get NULL 
    if(objname == NULL) 
    { 
    // Again, this should just propagate the exception information 
    return NULL; 
    } 

Ahora bien, hay un número de funciones en la sección String/Bytes Objects de los Concrete Objects Layer documentos; use el que sea mejor para usted.

Pero no se olvide este bit:

// Now that we're done with the object we obtained, decrement the reference count 
    Py_XDECREF(objname); 

    // You didn't mention whether you wanted to return a value from here, so let's just 
    // return the "None" singleton. 
    // Note: this macro includes the "return" statement! 
    Py_RETURN_NONE; 
} 

Nota el uso de Py_RETURN_NONE allí, y nota que no es return Py_RETURN_NONE!

PS. La estructura de este código está dictada en gran medida por el estilo personal (por ejemplo, retornos anticipados, cadenas de formato static char dentro de la función, inicialización en NULL). Esperemos que la información importante sea lo suficientemente clara aparte de las convenciones estilísticas.

+0

Muchas gracias. Cometí un error al hacer una pregunta. Cambié mi pregunta, en código python. Me disculpo por la pregunta aproximada. – Raymond

+0

@Raymond - sin preocupaciones, lo interpreté de esa manera de todos modos. – detly

+0

Ahora estoy obteniendo un arredump analizando args. PyArg_ParseTuple con "O" coredumps con Hombre ("John") aprobado. Los métodos [] se declaran con METH_VARARGS. Investigando ... – Raymond

Cuestiones relacionadas