2011-11-29 8 views
10

Mi sono imbattuto in una situazione con python puro e modulo C python. Per riassumere, come posso accettare e manipolare l'oggetto Python nel modulo C? La mia parte pitone sarà simile a questa.Passaggio di un oggetto al modulo C, in 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")) 

in C, due cose devono essere risolte. prima, come posso ricevere l'oggetto? in secondo luogo, come posso chiamare un metodo dall'oggetto?


    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

Aspetta, cosa stai passando a '_sayhello_obj'? E ''obj' (presumibilmente,' Man ("John") ')? O 'obj.getName()'? O è 'obj' nella funzione C in realtà' obj.getName() 'dalla chiamata Python? – detly

+0

Mi scuso. Ero addormentato quando ho fatto questa domanda. obj era ciò che volevo passare. obj.getName() è stato accidentalmente copiato dal mio esperimento. Ho aggiornato la domanda. – Raymond

+0

Bene, perché questa è la domanda che ho risposto! Lo sospettavo comunque. – detly

risposta

10

Per estrarre un argomento da un'invocazione del metodo, è necessario guardare le funzioni documentate in Parsing arguments and building values, come PyArg_ParseTuple. (Questo è per se stai solo argomentando posizionale! Ce ne sono altri per argomenti di positional-and-keyword, ecc.)

L'oggetto che torni da PyArg_ParseTuple non ha il numero di riferimenti aumentato. Per semplici funzioni C, probabilmente non devi preoccuparti di questo. Se stai interagendo con altre funzioni Python/C, o se stai rilasciando il lock dell'interprete globale (cioè consentendo il threading), devi pensare molto attentamente alla proprietà dell'oggetto.

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. 

Per chiamare un metodo su un oggetto, è necessario utilizzare uno o PyObject_CallMethodPyObject_CallMethodObjArgs, a seconda di come si costruisce la lista degli argomenti e il nome del metodo. E vedi il mio commento nel codice sulla proprietà dell'oggetto!

Breve digressione solo per assicurarsi che non ti stai preparando per un autunno più tardi: se ti stai solo strappando la stringa per stamparlo, è meglio ottenere il riferimento dell'oggetto e passarlo a PyObject_Print . Certo, forse questo è solo per l'illustrazione, o se si sa meglio di me che cosa si vuole fare con i dati;)

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

Ora ci sono una serie di funzioni nella sezione String/Bytes Objects dei Concrete Objects Layer documenti; usa quello che funziona meglio per te.

Ma non dimenticare questo 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 l'uso di Py_RETURN_NONE lì, e nota che non è return Py_RETURN_NONE!

PS. La struttura di questo codice è dettata in gran parte dallo stile personale (ad esempio, i resi anticipati, le stringhe di formato static char all'interno della funzione, l'inizializzazione su NULL). Speriamo che le informazioni importanti siano abbastanza chiare a parte le convenzioni stilistiche.

+0

Grazie mille. Ho fatto un errore facendo una domanda. Ho cambiato la mia domanda, in codice Python. Mi scuso per una domanda approssimativa. – Raymond

+0

@ Raymond - nessuna preoccupazione, l'ho comunque interpretato in questo modo. – detly

+0

Ora sto ottenendo un argomento di analisi sintattico. PyArg_ParseTuple con "O" coredumps con Man ("John") passato. i metodi [] sono dichiarati con METH_VARARGS. Ricercando .. – Raymond

Problemi correlati