Funktion zum Ausführen einer anderen Datei?

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.
Antworten
raiminator
User
Beiträge: 31
Registriert: Dienstag 1. Mai 2012, 08:06

Hey,

ich suche eine Funktion mit der man ein anderes Python-Programm ausführen kann.
ungefähr so in der Art:

Code: Alles auswählen

führeaus('test.py')
habe schon stundenlang gesucht, google und doku, bin da aber nur auf
os.system('test.py') gestoßen aber das öffnet die Datei nur im Editor...
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Warum willst du das tun? Normalerweise importiert man die nötigen Objekte (z.B. Klassen, Funktionen) und ruft diese auf und benutzt sie als Argumente in Funktionen. Also kein externer Systemaufruf.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Bevor du das hier nutzt, denk mal genau ueber derdons Post nach und erzaehle und am besten was du eigentlich erreichen willst.

Code: Alles auswählen

import subprocess, sys
subprocess.call([sys.executable, 'test.py'])
raiminator
User
Beiträge: 31
Registriert: Dienstag 1. Mai 2012, 08:06

Ich habe ein Quiz in Python geschrieben und dafür ein extra Start-Programm geschrieben, wo man dann das Quiz starten kann.
Das Startfenster soll sich halt schließen und da das schon so einiges an Code braucht fand ich es ziemlich unübersichtlich den Code fürs neue Fenster da mit reinzupacken. (übrigens ich arbeite mit tkinter)
Da ich aber das Quiz selbst zuerst geschrieben habe und das für mich als Anfänger ziemlich schwer ohne Globals zu realisieren war möchte ich das lieber so lassen (da man Globals bei Modulen nicht verwenden kann?)
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

raiminator hat geschrieben:Da ich aber das Quiz selbst zuerst geschrieben habe und das für mich als Anfänger ziemlich schwer ohne Globals zu realisieren war möchte ich das lieber so lassen (da man Globals bei Modulen nicht verwenden kann?)
Das klingt so als hättest du falsch begonnen und wolltest jetzt noch verkorkster weitermachen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@raiminator: Ergänzend zu /me, wieso postest Du uns nicht mal Dein Quiz (bitte bei längerem Code hier im Paste-Bin oder unter gist.github.com) und hörst Dir Verbesserungsvorschläge an?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
raiminator
User
Beiträge: 31
Registriert: Dienstag 1. Mai 2012, 08:06

da man im Pastebin nur Code hochladen kann hab ich mal alles als rar gepackt und woanders hochgeladen:
http://www.mediafire.com/?cdmfo5bgg9s75id
hoffe das hilft euch auch, jetzt sind noch ein paar sounds und bilder drin die das Programm verwendet.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Mit einer rar-Datei wirst du wahrscheinlich nicht viele dazu bringen sich den Code anzuschauen. Am besten ist es wahrscheinlich, wenn du den Code einfach im Paste-Bin postest. Wer das Quiz ausführen möchte, kann dann sich dann immer noch die von dir bereits hochgeladene Dateie holen.
Das Leben ist wie ein Tennisball.
BlackJack

@raiminator: Einige hier verwenden auch Linux oder MacOS, bei denen läuft das gar nicht erst wegen dem `winsound`-Modul, was wie der Name vermuten lässt, Windows-spezifisch ist. Da solltest Du vielleicht einen Rückfalllösung vorsehen. Zum Beispiel den `ImportError` behandeln und dort eine Dummy-Funktion `PlaySound()` mit zwei Argumenten und eine Konstante `SND_ASYNC` definieren.

Zur Form (Namenskonventionen, Leerzeichen, und so weiter) der obligatorische Hinweis auf PEP 8 -- Style Guide for Python Code.

Dann fallen gleich am Anfang die Sternchen-Importe auf. Die sollte man vermeiden, weil man sich damit potentiell unmengen von Namen in den Namensraum des Moduls holt. Es kann Kollisionen geben, man kann auch Sachen zurückgreifen die man gar nicht wollte wenn man sich zufällig irgend wo vertippt und einen importierten Namen erwischt, und so weiter.

Bei `Tkinter` ist es üblich ``import Tkinter as tk`` zu verwenden um sich Tipparbeit zu sparen.

Die globalen Variablen sind schlecht, weil dadurch die Funktionen auf sehr undurchsichtige Weise zusammenhängen. Auf Modulebene sollten nur Konstanten definiert werden. Alle Variablen und ausführbarer Code der nicht zur Definition von Konstanten verwendet wird, sollte von der Modulebene in Funktionen verschwinden. ``global`` solltest Du gar nicht verwenden.

Bei dem GUI-Entwurf sollte man absolute Grössen und `place()` vermeiden. Bei mir sieht die GUI zum Beispiel so aus:
Bild
Und ich denke nicht, dass das so aussehen sollte‽

Abkürzungen bei Namen sollte man vermeiden, wenn sie nicht wirklich allgemein bekannt sind. `rAntwort`, `telJoker`, `pubJoker`, `fifJoker`, und die Präfixe bei den GUI-Objekten `b`, `l`, und so weiter, sollte man verständlicher benennen.

„Denglisch” bei den Namen sollte man auch vermeiden. Entscheide Dich für Deutsch oder für Englisch, aber bitte nicht so etwas wie `getRandomFrage()` oder `newFrage`. Sowohl im Deutschen als auch im Englischen heisst es übrigens „Standar**d**”. ;-)

Nicht verwendetes sollte man entfernen. `risiko` zum Beispiel wird zwar zugewiesen, soweit ich sehe aber nirgends tatsächlich benutzt.

Werte und Zeichenketten mit `str()` und ``+`` zusammen zu setzen hat was von BASIC. In Python verwendet man dafür Zeichenkettenformatierung mittels ``%``-Operator oder der `format()`-Methode auf Zeichenketten.

Code: Alles auswählen

main.geometry(str(main_width) + 'x' + str(main_height))
# ->
main.geometry('%sx%s' % (main_width, main_height))
# oder
main.geometry('{0}x{1}'.format(main_width, main_height))
Man sollte bei Nummerierungen und Indexierungen nicht gegen den Rechner arbeiten. Zumindest intern fängt die Zählung bei 0 an. Die Nummer der richtigen Antwort sollte deshalb nicht zwischen 1 und 4 liegen, sondern zwischen 0 und 3. Dann kann man die Nummern auch als Index in Listen verwenden. Die `getBtn()`-Funktion wäre zum Beispiel um einiges kürzer wenn man eine Liste mit den `Button`-Exemplaren hätte und das Argument der Funktion einfach als Index verwenden würde. Eigentlich könnte man die Funktion komplett weglassen und statt des Aufrufs so etwas hier schreiben:

Code: Alles auswählen

        main.after(0, setgreen(answer_buttons[rAntwort - 1]))
Wenn die Antworten ab 0 nummeriert werden, kann man sich die ``- 1`` sparen.

In der Datenstruktur zu Fragen werden Daten mit unterschiedlichen Bedeutungen in der Liste vermischt. Die Antworten sollten in einer eigenen Liste zusammen gefasst werden. Dann kann man sie auch als ein Datum behandeln. Zum Beispiel kann man die Antworten mit `random.shuffle()` mischen und erhält so auf einfache Weise eine von *allen* möglichen Kombinationen und nicht nur die 4 Varianten, die Du hart kodiert hast, von den 24 Möglichkeiten die es gibt.

Mehrere Anweisungen auf einer Zeile durch Semikolons getrennt sollte man vermeiden, weil das die Lesbarkeit beeinträchtigen kann. In der `setFrage()`-Funktion würde man das sowieso kürzer schreiben können, wenn man die Antwort-`Button`\s wie schon vorgeschlagen in einer Liste speichern würde, denn dann könnte man eine Schleife verwenden, statt den selben Aufruf für jeden `Button` hin zu schreiben. Das könnte beispielsweise so aussehen:

Code: Alles auswählen

def set_question(question):
    global correct_answer_index, frage

    frage = question
    answers = question[1]
    correct_answer = answers[0]
    random.shuffle(answers)
    correct_answer_index = answers.index(correct_answer)
    
    question_label.configure(text=question[0])
    level_label.configure(text=level)
    for button, letter, answer, button in zip(answer_buttons, 'ABCD', answers):
        button.configure(text='%s: %s' % (letter, answer))
        set_blue(button)
Die `after()`-Aufrufe in `antwort()` sind so unsinnig weil Du dort keine Funktionen übergibst, sondern immer `None`. Ausnahme ist der letzte Aufruf im ``else``-Zweig wo tatsächlich eine Funktion übergeben wird. Bei allen anderen Aufrufen ist es völlig egal welche Wartezeit Du übergibst, weil Du die Funktionen selbst und sofort ausführst. Um hier Funktionen als zweites Argument zu übergeben brauchst Du `functools.partial` oder ``lambda``-Funktionen.

Die Gewinnstufe würde ich von konkreten Beträgen entkoppeln. Also nicht die Beträge an `level` binden, sondern die Stufe einfach von 0 an hochzählen und eine Funktion schreiben, welche die Stufe für die Anzeige in einen Betrag umrechnet. Dann kann man da zum Beispiel für die Anfangsstufen mit einer Liste arbeiten und sich die vielen ``if``/``elif`` sparen, die in `getNextLevel()` stehen.

Bei den Schaltflächen für die Antworten ignorierst und umgehst Du eigentlich alle Eigenschaften die `Button` bietet und implementierst sie teilweise selbst. Entweder nutzt Du den `Button` mehr, oder Du solltest etwas anderes verwenden.

Ich denke hier kommt man um eigene Klassen nicht herum wenn man das sauber lösen möchte. Dabei sollte man das Spiel ohne GUI-Code kapseln. Und bei der GUI würden eigene Datentypen für einzelne Antwortschaltfächen und eins für die Antwortschaltflächen als Gruppe Sinn machen.

@EyDu: Was gibt's an RAR auszusetzen? Zumindest Entpacker gibt es kostenlos und frei für die gängigen Betriebssysteme und die meisten Werkzeuge die mit mehreren Formaten umgehen können, entpacken die Archive auch. Das Format ist in der Regel besser als ZIP und schon seit Urzeiten (== DOS-Zeiten) verbreitet. Ich könnte so eine Bemerkung vielleicht bei 7z- oder tar.xz- Archiven verstehen, weil die noch relativ neu sind. Aber verbreitet sind die auch.
raiminator
User
Beiträge: 31
Registriert: Dienstag 1. Mai 2012, 08:06

Danke natürlich dass du dir da so viel mühe gegeben hast :)
An das mit den sounds hatte ich da jetzt überhauptnicht gedacht..
Wie gesagt, ich bin ein Python-Neuling und auf das mit der Namenskonvention wurde ich schon häufig hingewiesen, wenn ich Zeit habe lese ich es mir mal durh.

soo viele Funktionen sind es nicht, die ich da hab deshalb dachte ich dass man den Sternchenimport von tkinter noch machen kann, sonst habe ich das auch immer so gemacht.

Naja, das mit den Globals habe ich ja schon angesprochen, für mich war das bei dem Quiz am einfachsten und ich kann mir grade auch nicht vorstellen wie das anders gehen soll (wie gesagt bin ein Anfänger)

Der GUI-Entwurf sieht bei mir genauso aus, soll auch noch nicht anders weil es noch ein Entwurf ist.
Das mit den Abkürzungen ist mir auch immer unübersicbhtlicher geworden, änder ich noch ;)
Auch das mit den Nummerierungen der Buttons und der zufälligen Verteilung änder ich noch gerne, vielen Dank für die Tipps :)

Leider kenne ich mich auch mit oop noch nicht sonderlich gut aus, ich guck mal ob ich das hinkriege mit den Klassen..
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich würde Deinen Code ja auch mal durchgehen, aber auf einen Archiv-Download habe ich keine Lust ;-) Wieso befolgst Du nicht EyDus Vorschlag?

Ich habe selber mal ein kleines Quiz zur Demonstration geschrieben. Evtl. kannst Du Dir da einiges abgucken - es hat halt keine GUI. Aber es kommt ohne globale Variablen aus. Eigentlich ist das auch nicht so schwer. Man muss eben die benötigten Daten an die einzelnen Funktionen übergeben. Oder man sammelt zusammengehörige Daten und Funktionen in Klassenobjekten :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
raiminator
User
Beiträge: 31
Registriert: Dienstag 1. Mai 2012, 08:06

habs jetzt nochmal im Pastebin hochgeladen, aber unverändert (beim ausführen gibt's errors wegen bildern und sounds)

ich wollte jetzt mal versuchen eine Klasse zu erstellen für den Antwort-Button. Da schon die erste Frage:
Der Button sollte ja den Tkinter-Button extenden. geht das in dem FAll dann so:

Code: Alles auswählen

import Tkinter as tk
class answer_button(tk.Button):
    def __init__(...):
        ...
Und wird, wenn ich den Konstruktor aufrufe, der Tk-Button automatisch erstellt oder muss man im Konstruktor sowas wie in Java super() aufrufen?
Zuletzt geändert von Anonymous am Samstag 26. Mai 2012, 14:45, insgesamt 1-mal geändert.
Grund: Link zum Paste eingefügt
BlackJack

@raiminator: Wenn Du eine eigene `__init__()` definierst, musst Du die `__init__()` von Elternklassen gegebenenfalls selber aufrufen. Wenn Du das hier verstanden hast und danach `super()` noch super findest: http://fuhm.net/super-harmful/ kannst Du `super()` verwenden, ansonsten würde ich explizites Aufrufen der entsprechenden `__init__()` über die Elternklasse(n) empfehlen.
raiminator
User
Beiträge: 31
Registriert: Dienstag 1. Mai 2012, 08:06

meinst du das so?

Code: Alles auswählen

# Antwort-Button-Klasse
class answer_button(tk.Button):
    def __init__(self, parent):
        tk.Button.__init__(self, parent, image=BTN_BG)
        self.config(text='Hallo')
        self.pack()
funktioniert bei mir jedenfalls :D
BlackJack

@raiminator: Ja so kann man das machen was den Aufruf der `__init__()` von der Elternklasse angeht. Der `pack()`-Aufruf gehört da aber nicht hin. Das machen die anderen `Tkinter`-Widgets ja auch nicht. Welcher Layout-Manager verwendet werden soll ist Sache des Aufrufers. Der möchte vielleicht den Button gar nicht mit `pack()` sondern mit `grid()` anordnen lassen.

Die Klasse sollte nach der üblichen Namenskonvention `AnswerButton` heissen.

Kommentare sollten einen Mehrwert liefern. Wenn im Kommentar etwas steht was gleich darauf ganz offensichtlich noch einmal als Quelltext steht, dann sollte man den Kommentar weg lassen. Im Idealfall kann man im Quelltext lesen *was* gemacht wird, und Kommentare sind dazu da dem Leser zu sagen *warum* etwas so gemacht wird, wie es im Quelltext gemacht wird — falls das nicht schon aus dem Quelltext ersichtlich ist.
raiminator
User
Beiträge: 31
Registriert: Dienstag 1. Mai 2012, 08:06

ok, das mit Namenskonvention habe ich mich jetzt noch nicht auseinandergesetzt, soll man also bei Funktionen mehr unterstriche verwenden bei Klassen aber Groß/Kleinschreibung?
BlackJack

@raiminator: Namenskonventionen werden hier behandelt: PEP 8 -- Style Guide for Python Code
Antworten