Warum führt Python mein Modul aus, wenn ich es importiere, und wie stoppe ich es?

171

Ich habe ein Python-Programm, das ich erstelle und das auf zwei Arten ausgeführt werden kann: Die erste besteht darin, "python main.py" aufzurufen, die den Benutzer auf freundliche Weise zur Eingabe auffordert und dann die Benutzereingaben über das Programm ausführt. Die andere Möglichkeit besteht darin, "python batch.py -file- " aufzurufen, das alle benutzerfreundlichen Eingabesammlungen durchläuft und die Eingaben einer ganzen Datei in einem Durchgang durch das Programm ausführt .

Das Problem ist, dass beim Ausführen von "batch.py" einige Variablen / Methoden / etc aus "main.py" importiert werden und dieser Code ausgeführt wird:

import main

In der ersten Zeile des Programms tritt sofort ein Fehler auf, da versucht wird, den Code in "main.py" auszuführen.

Wie kann ich verhindern, dass Python den Code aus dem "Haupt" -Modul ausführt, das ich importiere?

Dasmowenator
quelle

Antworten:

249

Denn so funktioniert Python - Schlüsselwörter wie classund defsind keine Deklarationen . Stattdessen handelt es sich um echte Live-Anweisungen, die ausgeführt werden. Wenn sie nicht ausgeführt würden, wäre Ihr Modul .. leer :-)

Wie auch immer, der idiomatische Ansatz ist:

# stuff to run always here such as class/def
def main():
    pass

if __name__ == "__main__":
   # stuff only to run when not called via 'import' here
   main()

Siehe Wofür ist if __name__ == "__main__"?

Es erfordert jedoch eine Quellcodeverwaltung über das zu bearbeitende Modul import.

Viel Spaß beim Codieren.


quelle
1
Nur um zu bestätigen, impliziert Ihr Kommentar "Sachen, die nur ausgeführt werden sollen, wenn sie nicht über 'Import' hier aufgerufen werden" die Befehle, die unter main () geschrieben werden sollen, oder? Oder spielt es keine Rolle?
Goldname
@Goldname Der Code in der if-Anweisung wird beim Import nicht ausgeführt, aber die Hauptfunktion an sich ist definiert und kann auch durch einen Import verwendet werden. Dieses Modul würde die Hauptfunktion nur ausführen, wenn sie ausgeführt wird, und sie nicht ausführen, wenn sie importiert wird. Es hängt alles davon ab, was Sie tun möchten. Wenn Sie die Befehle in main nicht an anderer Stelle benötigen, schreiben Sie sie auf jeden Fall in das if. Aber für mich sieht es ordentlicher aus.
Felix
51

Aufgrund der Funktionsweise von Python müssen Ihre Module beim Import ausgeführt werden.

Um zu verhindern, dass Code im Modul beim Import ausgeführt wird, aber nur bei direkter Ausführung, können Sie ihn folgendermaßen schützen if:

if __name__ == "__main__":
    # this won't be run when imported

Möglicherweise möchten Sie diesen Code in eine main()Methode einfügen , damit Sie die Datei entweder direkt ausführen oder das Modul importieren und das aufrufen können main(). Angenommen, dies befindet sich in der Datei foo.py.

def main():
    print "Hello World"

if __name__ == "__main__":
    main()

Dieses Programm kann entweder über go python foo.pyoder über ein anderes Python-Skript ausgeführt werden:

import foo

...

foo.main()
Jeremy Banks
quelle
12

Verwenden Sie das if __name__ == '__main__'Idiom - __name__ist eine spezielle Variable, deren Wert ist, '__main__'wenn das Modul als Skript ausgeführt wird, und der Modulname, wenn es importiert wird. Also würdest du so etwas machen

# imports
# class/function definitions
if __name__ == '__main__':
    # code here will only run when you invoke 'python main.py'
Ismail Badawi
quelle
4

Das tust du leider nicht. Dies ist ein Teil der Funktionsweise der Importsyntax, und es ist wichtig, dass dies der Fall ist. Denken Sie daran, dass deftatsächlich etwas ausgeführt wird. Wenn Python den Import nicht ausgeführt hat, stecken Sie ohne Funktionen fest.

Da Sie wahrscheinlich Zugriff auf die Datei haben, können Sie möglicherweise nachsehen, was den Fehler verursacht. Möglicherweise können Sie Ihre Umgebung ändern, um zu verhindern, dass der Fehler auftritt.

cwallenpoole
quelle
1
Als Hinweis: Wenn es keine Möglichkeit gibt, die Umgebung so zu ändern, dass der Fehler verhindert werden kann, sollten Sie möglicherweise ein anderes Modul verwenden
cwallenpoole
4

Fügen Sie den Code in eine Funktion ein und er wird erst ausgeführt, wenn Sie die Funktion aufrufen. Sie sollten eine Hauptfunktion in Ihrem haben main.py. mit der Aussage:

if __name__ == '__main__':
  main()

Wenn Sie dann aufrufen, wird python main.pydie main()Funktion ausgeführt. Wenn Sie importieren main.py, wird es nicht. Außerdem sollten Sie der main.pyÜbersichtlichkeit halber wahrscheinlich in etwas anderes umbenennen .

Matt
quelle
3

Es gab einen Python-Erweiterungsvorschlag PEP 299, der darauf abzielte, die if __name__ == '__main__':Redewendung durch zu ersetzen def __main__:, der jedoch abgelehnt wurde. Es ist immer noch eine gute Lektüre, um zu wissen, was bei der Verwendung zu beachten ist if __name__ = '__main__':.

Paul Tobias
quelle
2

Sie können Ihre "main.py" folgendermaßen schreiben:

#!/usr/bin/env python

__all__=["somevar", "do_something"]

somevar=""

def do_something():
    pass #blahblah

if __name__=="__main__":
    do_something()
hgoldfish
quelle
-1

Obwohl Sie nicht verwenden können, importohne den Code auszuführen; Es gibt eine ziemlich schnelle Möglichkeit, Ihre Variablen einzugeben. mit using numpy.savez, das Variablen als numpy-Arrays in einer .npz-Datei speichert. Anschließend können Sie die Variablen mit laden numpy.load.

Eine vollständige Beschreibung finden Sie in der Scipy-Dokumentation

Bitte beachten Sie, dass dies nur für Variablen und Arrays von Variablen der Fall ist und nicht für Methoden usw.

user3569257
quelle
-4

Versuchen Sie einfach, die benötigten Funktionen aus main.py zu importieren. So,

from main import SomeFunction

Es kann sein, dass Sie eine Funktion in batch.py ​​genauso benannt haben wie eine in main.py, und wenn Sie main.py importieren, führt das Programm die Funktion main.py anstelle der Funktion batch.py ​​aus. Wenn Sie dies tun, sollte dies behoben sein. Ich hoffe.

Dave Lewis
quelle
Zumindest unter Windows nicht.
Martín Coll
2
import mainimportiert NICHT alles von main in den aktuellen Namespace. Es wird nur ein einziges mainSymbol in den aktuellen Namespace eingefügt, sodass keine Kollisionen auftreten können.
Remram