2013-10-16 8 views
6

Sto scrivendo un programma Go. Da questo programma Go, vorrei chiamare una funzione Python definita in un altro file e ricevere il valore di ritorno della funzione in modo che possa usarla nell'elaborazione successiva nel mio programma Go. Tuttavia, ho problemi a recuperare i dati restituiti nel mio programma Go. Di seguito è riportato un esempio minimo di quello che pensavo avrebbe funzionato, ma a quanto pare non si:Chiamare la funzione Python da Go e ottenere il valore restituito dalla funzione

gofile.go

package main 

import "os/exec" 
import "fmt" 

func main() { 
    fmt.Println("here we go...") 
    program := "python" 
    arg0 := "-c" 
    arg1 := fmt.Sprintf("'import pythonfile; print pythonfile.cat_strings(\"%s\", \"%s\")'", "foo", "bar") 
    cmd := exec.Command(program, arg0, arg1) 
    fmt.Println("command args:", cmd.Args) 
    out, err := cmd.CombinedOutput() 
    if err != nil { 
     fmt.Println("Concatenation failed with error:", err.Error()) 
    return 
    } 
    fmt.Println("concatentation length: ", len(out)) 
    fmt.Println("concatenation: ", string(out)) 
    fmt.Println("...done") 
} 

pythonfile.py

def cat_strings(a, b): 
    return a + b 

Se chiamo go run gofile Ottengo il seguente risultato:

here we go... 
command args: [python -c 'import pythonfile; print pythonfile.cat_strings("foo", "bar")'] 
concatentation length: 0 
concatenation: 
...done 

Alcune note:

  • sto usando la bandiera -c nell'invocazione Python in modo da poter chiamare la funzione cat_strings direttamente. Si supponga che cat_strings sia parte di un file Python pieno di funzioni di utilità utilizzate da altri programmi Python, quindi perché non ho alcuna attività commerciale if __name__ == __main__.
  • Non voglio modificare il file Python su print a + b (anziché su return a + b); si veda il punto precedente sulla funzione che fa parte di un insieme di funzioni di utilità che dovrebbero essere richiamabili da un altro codice Python.
  • La funzione cat_strings è fittizia ea scopo dimostrativo; la vera funzione è qualcosa che non voglio semplicemente reimplementare in Go. Sono davvero interessato a come posso chiamare una funzione Python di Go e ottenere il valore di ritorno.
+0

Ho la sensazione che questo non possa essere fatto facilmente usando 'os/exec'. Tutte le funzioni 'os/exec' restituiscono solo stdout e/o stderr. – Intermernet

+0

Dai un'occhiata a https://github.com/sbinet/go-python e http://stackoverflow.com/questions/12443203/writing-a-python-extension-in-go-golang – Intermernet

+0

@Intermernet Ho pensato che il mio chiama a 'print' in python python -c 'import pythonfile; print pythonfile.cat_strings ("foo", "bar") "" verrebbe stampato su stdout. –

risposta

8

sono riuscito ad avere un po 'di codice di lavoro per questo semplicemente rimuovendo la citazione attorno al comando stesso:

package main 

import "fmt" 
import "os/exec" 

func main() { 
    cmd := exec.Command("python", "-c", "import pythonfile; print pythonfile.cat_strings('foo', 'bar')") 
    fmt.Println(cmd.Args) 
    out, err := cmd.CombinedOutput() 
    if err != nil { fmt.Println(err); } 
    fmt.Println(string(out)) 
} 

E infatti, nel source, si dispone di questa funzione (per Windows, almeno , non so se funziona per altri sistemi operativi):

// EscapeArg rewrites command line argument s as prescribed 
// in http://msdn.microsoft.com/en-us/library/ms880421. 
// This function returns "" (2 double quotes) if s is empty. 
// Alternatively, these transformations are done: 
// - every back slash (\) is doubled, but only if immediately 
// followed by double quote ("); 
// - every double quote (") is escaped by back slash (\); 
// - finally, s is wrapped with double quotes (arg -> "arg"), 
// but only if there is space or tab inside s. 
func EscapeArg(s string) string { ... 

Quindi il codice è di finire passando la seguente chiamata riga di comando:

$ python -c "'import pythonfile; print pythonfile.cat_strings(\\"foo\\", \\"bar\\")'" 

Che, se testato, restituisce una stringa e non restituisce nulla, quindi l'output di lunghezza 0.

+0

Appena testato su Linux (Ubuntu) e rimuovendo le citazioni singole funziona, quindi sembra essere una soluzione multipiattaforma. –

+4

Bello! Felice di aiutare. Sebbene, come suggerito da altri, se si debba fare un uso massiccio di questo, è meglio usare i collegamenti API CPython o utilizzare un'interfaccia di rete per comunicare tra Python e Go. – val

Problemi correlati