Daten an Subprocess übergeben bzw. im Subprocess auslesen ?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
snakeseven
User
Beiträge: 408
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Hallo,
ich habe mich in die Pipe-, Popen-, Subprocess- Sachen ein wenig eingelesen, aber bin doch verwirrt, wie das alles funktioniert. Ich will Folgendes:

Main Hauptprogramm ruft mit

Code: Alles auswählen

pz1 = subprocess.Popen('C:/Python/dist/Modul_1.exe')
ein anderes Programm auf. In diesem Programm sollen zwei Variablen weiterverarbeitet werden,
welche vom aufrufenden Programm übergeben werden sollen. Wie bekomme ich:

a) die Variablen (z.b. x und y) über subprocess() in das andere Programm transferiert (write ?, return ?,send ?)

b) wie lese ich in dem anderen Programm die übergebenen Daten aus (read ? readline ? input ?)

Ich weiss, es gibt 'stin' und 'stout'. Aber wie kommunizieren die miteinander ? Hat vieleicht einer ein klitzekleines, konkretes Beispiel parat ?

Wäre sehr dankbar !
Seven
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

read() liest von stdout des Subprocesses, write() schreibt an stdin des Subprozesses
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:


GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

snakeseven hat geschrieben:Ich weiss, es gibt 'stin' und 'stout'. Aber wie kommunizieren die miteinander ? Hat vieleicht einer ein klitzekleines, konkretes Beispiel parat ?
Hi Seven!

Vielleicht bringt dich das weiter:
http://www.python-forum.de/viewtopic.php?p=29406#29406

Das soll aber nur eine der vielen Möglichkeiten darstellen.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hi Seven!

Wenn du das aufrufende Programm auch mit anderen Programmiersprachen oder einfach nur über die Shell aufrufen können möchtest, dann solltest du darüber nachdenken, ob es nicht doch besser ist, die Parameter über die Kommandozeile zu übergeben zu lassen.

Wie so etwas aussehen kann, demonstriert folgendes Skript. (siehe `def parse_options():`)
http://www.python-forum.de/viewtopic.php?p=9536#9536

Lass dich bitte nicht von den vielen möglichen Parametern im Programm abschrecken. So etwas funktioniert auch mit weniger. ;-)

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
snakeseven
User
Beiträge: 408
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Vielen Dank !!
Das sieht genau nach dem aus, was ich suche.
Bei mir ruft ein Pythonscript ein anderes (compiliertes) Pythonscript auf, das dürfte mit den Infos jetzt funktionieren. Werde mich gleich morgen ranmachen, es auszuprobieren.

Grüße, Seven
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Ich hab das erste Beispiel http://www.python-forum.de/viewtopic.php?t=4941 von Gerold ein bisschen verändert, weil mittels cPickle.load/dump auch bidirektionale Kommunikation möglich ist. Wenn Dich das interessiert, guck nochmal mach.

--- Heiko.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

snakeseven hat geschrieben:Bei mir ruft ein Pythonscript ein anderes (compiliertes) Pythonscript auf
Moment mal! Du rufst ein anderes Python-Skript auf? Warum dann überhaupt über subprocess???
Warum importierst du es nicht einfach und rufst gezielt eine Methode/Funktion auf?
Eine andere Möglichkeit wird beim Python-Server gemacht, es ruft das andere Skript über execfile() auf.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
snakeseven
User
Beiträge: 408
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Moment mal! Du rufst ein anderes Python-Skript auf? Warum dann überhaupt über subprocess???
Warum importierst du es nicht einfach und rufst gezielt eine Methode/Funktion auf?
Eine andere Möglichkeit wird beim Python-Server gemacht, es ruft das andere Skript über execfile() auf.
Es ist ein wenig komplexer. Ein Hauptprozess ruft je nach Bedarf Nebenprozesse auf und terminiert die anschließend wieder. Diese Nebenprozesse bekommen Daten übergeben, arbeiten sie ab und tschüss.
Das ganze ist eine serverbasiserte Anwendung, die je nach Anforderung des Users ein eigenes, auf diese Anforderung zugeschnittenes Programm startet. Der Prozesshandler hat zudem die Aufgabe, die Funktionstüchtigkeit der Nebenprozesse zu überprüfen und erstellt Fehler- und andere Protokolle. Ich finde die Lösung mit den Subprozessen am einfachsten, weil dann auch mehrere parallel arbeiten können. Mit execfile() oder Popen2() kann ich Programme zwar starten, aber nicht wieder beenden. Ist mir jedenfalls nicht gelungen.

Gruss, Seven
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Nimmt man dafür dann nicht besser RPC ?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
snakeseven
User
Beiträge: 408
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

jens hat geschrieben:Nimmt man dafür dann nicht besser RPC ?
Kenn ich nicht !? Noch ne neue Baustelle wollte ich eigendlich nicht aufmachen. :roll: Werde mich aber mal damit beschäftigen. Danke für den Tipp ! Seven
snakeseven
User
Beiträge: 408
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

@Gerold: Hi, wenn ich dein Sender-Empfänger Beispiel starte, bekome ich eine Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:/Ablage/Python/PythonScripte/sender.py", line 54, in -toplevel-
    main()
  File "C:/Ablage/Python/PythonScripte/sender.py", line 38, in main
    cwd = os.curdir
  File "C:\Programme\Python24\lib\subprocess.py", line 533, in __init__
    (p2cread, p2cwrite,
  File "C:\Programme\Python24\lib\subprocess.py", line 623, in _get_handles
    errwrite = self._make_inheritable(errwrite)
  File "C:\Programme\Python24\lib\subprocess.py", line 634, in _make_inheritable
    DUPLICATE_SAME_ACCESS)
TypeError: an integer is required
Gruss, Seven
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

snakeseven hat geschrieben:@Gerold: Hi, wenn ich dein Sender-Empfänger Beispiel starte, bekome ich eine Fehlermeldung:
[...]
TypeError: an integer is required[/code]
Hi Seven!

Ich bin paff -- ehrlich. :shock:
Soeben habe ich das Skript unter Windows getestet. So wie ich meistens einen **kleinen** Test unter Windows mache. -- Mit Idle. --

Ich habe die gleiche Fehlermeldung wie du bekommen. Nach ein paar Minuten des sinnlosen herumprobierens habe ich das Skript im WingIDE geöffnet, damit ich besser debuggen kann. Siehe da im WingIDE funktionierte es ohne Probleme. Dann probierte ich es noch über die Kommandozeile aus. Ebenfalls kein Problem.

Das ist mein erstes Skript, das sich nicht dazu überreden lässt, im Idle zu funktionieren.

Vielleicht funktioniert es ja mit **os.popen2** im Idle, aber das kannst du ja selber ausprobieren.

lg
Gerold
:-)
Zuletzt geändert von gerold am Mittwoch 18. Januar 2006, 10:27, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Und wieder ein Grund mehr von der IDLE abzuraten ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
snakeseven
User
Beiträge: 408
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Hi,
ich muss nochmal zum grundsätzlichen Verständnis nachbohren:
Stdin und Stdout sind der Standardinput bzw. - Output von was: subprocess ?, sys ?
Ich gehe jetzt erstmal davon aus, dass Stdin/Stdout existieren und mir zur Verfügung stehen:

Beispiel: Ich habe zwei Prozesse, einen Main- und einen Subprozess.

Möglichkeit 1:
Mit subproz.stdin.write() schickt der Mainprozess Daten an Stdin.
Mit sys.stdin.read() holt sich der Subprozess die Daten dort ab.
Würde der Subprozess widerum Daten erzeugen, so könnte er diese mit sys.stdout.write()
an Stdout schicken. Und der Mainprozess könnte sie sich dort mit
prozess.stdout.read() abholen.

Möglichkeit 2:
Auf Stdin kann immer nur write() angewendet werden und auf Stdout immer nur read().
Das hieße, daß der Mainprozess mit subproz.stdin.write() die Daten an den Stdin vom Subprozess schickt.
Aus der Sicht vom Subprozess gibt es aber kein Stdin sondern nur den Stdout des Mainprozesses.
Also muss sich Subprozess die Daten mit sys.stdout.read() dort abholen. Das hieße, wenn ich mich nicht irre,
daß physikalisch Stdin = Stdout ist ?

Sorry für eventuelle Verwirrung, aber nur so kann ich verstehen, was ich da überhaupt mache.
Gruss, Seven
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Möglichkeit 1 ist das richtige. ;-)

Die Dokumentation vom subprocess-Modul müßte den Rest erklären.

--- Heiko.
snakeseven
User
Beiträge: 408
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

modelnine hat geschrieben:Möglichkeit 1 ist das richtige. ;-)
--- Heiko.
Ahhh ! Bin ich ja doch schonmal ein bischen weiter :D
Dennoch verstehe ich dann nicht, wieso mir dieses Minibeispiel

Code: Alles auswählen

#Daten an Subprozess schicken
import subprocess
p = subprocess.Popen('C:/Ablage/Python/PythonScripte/test.py',stdin = subprocess.PIPE)
raus = "10" + "20" + "Fred vom Jupiter"
p.stdin.write(raus)
p.close()
folgende Fehlermeldungen erzeugt:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Ablage\Python\PythonScripte\test2.py", line 3, in -toplevel-
    p = subprocess.Popen('C:/Ablage/Python/PythonScripte/test.py',stdin = subprocess.PIPE)
  File "C:\Programme\Python24\lib\subprocess.py", line 533, in __init__
    (p2cread, p2cwrite,
  File "C:\Programme\Python24\lib\subprocess.py", line 607, in _get_handles
    c2pwrite = self._make_inheritable(c2pwrite)
  File "C:\Programme\Python24\lib\subprocess.py", line 634, in _make_inheritable
    DUPLICATE_SAME_ACCESS)
WindowsError: [Errno 6] Das Handle ist ungültig
Und dieses Beispiel bemängelt der Interpreter auch:

Code: Alles auswählen

#übergebene Daten auslesen
import sys
print sys.stdout.read()

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Ablage\Python\PythonScripte\test.py", line 2, in -toplevel-
    print sys.stdout.read()
AttributeError: read
Gruss, Seven
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

So geht's:
test.py

Code: Alles auswählen

import subprocess

p = subprocess.Popen("python test2.py", stdin = subprocess.PIPE)
p.stdin.write("Fred vom Jupiter")
p.stdin.close()

print "ende"
test2.py

Code: Alles auswählen

import sys

print "OK1"
print "XXX%sXXX" % sys.stdin.readline()
print "OK2"
Allerdings ist das bei mir eine wackelige Geschichte... Wenn ich es in Scite Teste, dann muß bei test.py das print "ende" drin sein. Wenn ich das auskommentiere, geht es mal und dann wieder nicht...
Wenn ich es auf der Eingabeaufforderung teste, dann muß ich immer zum Schluß ein Enter drücken, damit der Interpreter beendet wird... Ich habe es auch mal versucht, vor dem p.stdin.close() ein p.stdin.write(os.linesep) einzufügen, damit readline() auf jeden Fall "weiter" macht. Das Ergebniss ist das selbe...

Und das bringt auch nichts:

test2.py

Code: Alles auswählen

import sys

print "OK"
while 1:
    line = sys.stdin.readline()
    if not line:
        break
    print line
print "OK2"

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
snakeseven
User
Beiträge: 408
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

@ Jens: Danke dir, werds gleich mal checken.

@ Gerold: Kannst du mir noch sagen, wieso in
deinem Beispiel cPickle.dumps (mit's') verwendet wird ? Habe dazu auch bei Google nichts gefunden und in der Python Referenz, wie leider so oft, auch nichts.

Gruss, Seven
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

snakeseven hat geschrieben:@ Gerold: Kannst du mir noch sagen, wieso in
deinem Beispiel cPickle.dumps (mit's') verwendet wird ? Habe dazu auch bei Google nichts gefunden und in der Python Referenz, wie leider so oft, auch nichts.
Hi Seven!

Da ich davon gehört habe, dass unter Windows das Zielprogramm abgebrochen wird, wenn über sys.stdin des Zielprogramms der String "\x1a" geleitet wird, dachte ich mir, dass es besser sei, keine binären Daten über STDIN zu jagen. Da in der Erklärung von "cPicle.dumps" steht, dass damit ein String erzeugt wird, dachte ich mir, dass "dumps" sich schon darum kümmern wird, dass kein "EOF" (="\x1a") mitten im String auftauchen wird. Aber wahrscheinlich wird "dumps" exakt den gleichen Code erzeugen, wie ihn "dump" erzeugt.

Der einzige Unterschied wird also sein, dass ich vorher einen String erzeuge und diesen mit "write()" über die Leitung jage und in der Version von modelnine wird dieser Schritt ausgelassen, da "dump" sich schon darum kümmert, dass die Daten in das "File"-Objekt (in diesem Fall: STDIN des Kindprozesses) geschrieben wird.

http://python.org/doc/2.4.2/lib/node65.html

Das "BIN"-Problem besteht aber trotzdem noch, da ich ja beim "dumps" als Protokoll die Zahl 2 angegeben habe. Das war evt. nicht so gut. Hätte ich das nicht angegeben, dann würde mit Sicherheit ein "ASCII"-String generiert werden. Andererseits glaube ich nicht, dass mit "Pickle" etwas generiert wird, was den Datenfluss abbrechen könnte.

http://www.python-forum.de/viewtopic.php?p=29095#29095

lg
Gerold
:-)
Zuletzt geändert von gerold am Donnerstag 19. Januar 2006, 10:12, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten