Pourquoi Python exécute-t-il mon module lorsque je l'importe et comment l'arrêter?

173

J'ai un programme Python que je construis qui peut être exécuté de deux manières: la première est d'appeler "python main.py" qui invite l'utilisateur à entrer de manière conviviale, puis exécute l'entrée de l'utilisateur via le programme. L'autre façon est d'appeler "python batch.py -file- " qui passera sur toute la collecte des entrées conviviales et exécutera la valeur d'un fichier entier à travers le programme en une seule fois.

Le problème est que lorsque j'exécute "batch.py", il importe des variables / méthodes / etc depuis "main.py", et lorsqu'il exécute ce code:

import main

à la première ligne du programme, il se trompe immédiatement car il essaie d'exécuter le code dans "main.py".

Comment puis-je empêcher Python d'exécuter le code contenu dans le module "principal" que j'importe?

Dasmowenator
la source

Réponses:

251

Parce que c'est ainsi que fonctionne Python - des mots clés tels que classet nedef sont pas des déclarations . Au lieu de cela, ce sont de vraies instructions en direct qui sont exécutées. S'ils n'étaient pas exécutés, votre module serait .. vide :-)

Quoi qu'il en soit, l'approche idiomatique est:

# 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()

Voir À quoi ça sert if __name__ == "__main__"?

importCependant, cela nécessite un contrôle de la source sur le module en cours d' édition.

Bon codage.


la source
1
juste pour confirmer, votre commentaire "trucs à exécuter uniquement lorsqu'ils ne sont pas appelés via 'import' ici" implique les commandes à écrire sous main (), non? Ou ça n'a pas d'importance ??
Goldname
@Goldname Le code à l'intérieur de l'instruction if ne sera pas exécuté lors de l'importation, mais la fonction principale en elle-même est définie et prête à être utilisée même via une importation. Ce module exécutera simplement la fonction principale lors de son exécution et ne l'exécutera pas s'il est importé. Tout dépend de ce que vous voulez faire. Si vous n'avez pas besoin des commandes dans main ailleurs, écrivez-les dans le if. Mais pour moi, ça a l'air plus soigné.
Felix
51

En raison du fonctionnement de Python, il est nécessaire qu'il exécute vos modules lorsqu'il les importe.

Pour empêcher le code du module d'être exécuté lors de l'importation, mais uniquement lorsqu'il est exécuté directement, vous pouvez le protéger avec ceci if:

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

Vous souhaiterez peut-être placer ce code dans une main()méthode, afin de pouvoir exécuter le fichier directement ou importer le module et appeler le main(). Par exemple, supposons que ce soit dans le fichier foo.py.

def main():
    print "Hello World"

if __name__ == "__main__":
    main()

Ce programme peut être exécuté soit en allant python foo.py, soit à partir d'un autre script Python:

import foo

...

foo.main()
Jeremy Banks
la source
12

Utilisez l' if __name__ == '__main__'idiome - __name__est une variable spéciale dont la valeur est '__main__'si le module est exécuté en tant que script, et le nom du module s'il est importé. Alors tu ferais quelque chose comme

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

Malheureusement, vous ne le faites pas. Cela fait partie du fonctionnement de la syntaxe d'importation et il est important que ce soit le cas - rappelez-vous que defc'est en fait quelque chose qui est exécuté, si Python n'exécutait pas l'importation, vous seriez, eh bien, bloqué sans fonctions.

Étant donné que vous avez probablement accès au fichier, vous pourrez peut-être rechercher et voir ce qui cause l'erreur. Il peut être possible de modifier votre environnement pour empêcher l'erreur de se produire.

cwallenpoole
la source
1
À noter: s'il n'y a aucun moyen de modifier l'environnement afin d'éviter l'erreur, vous devriez peut-être utiliser un module différent
cwallenpoole
4

Mettez le code dans une fonction et il ne fonctionnera pas tant que vous n'aurez pas appelé la fonction. Vous devriez avoir une fonction principale dans votre main.py. avec la déclaration:

if __name__ == '__main__':
  main()

Ensuite, si vous appelez, python main.pyla main()fonction s'exécutera. Si vous importez main.py, ce ne sera pas le cas. De plus, vous devriez probablement renommer main.pyquelque chose d'autre pour des raisons de clarté.

Mat
la source
3

Il y avait une proposition d'amélioration de Python PEP 299 qui visait à remplacer l' if __name__ == '__main__':idiome par def __main__:, mais elle a été rejetée. C'est toujours une bonne lecture pour savoir ce qu'il faut garder à l'esprit lors de l'utilisation if __name__ = '__main__':.

Paul Tobias
la source
2

Vous pouvez écrire votre "main.py" comme ceci:

#!/usr/bin/env python

__all__=["somevar", "do_something"]

somevar=""

def do_something():
    pass #blahblah

if __name__=="__main__":
    do_something()
gros poisson
la source
-1

Bien que vous ne puissiez pas utiliser importsans exécuter le code; il existe une manière assez rapide de saisir vos variables; en utilisant numpy.savez, qui stocke les variables sous forme de tableaux numpy dans un fichier .npz. Ensuite, vous pouvez charger les variables en utilisant numpy.load.

Voir une description complète dans la documentation scipy

Veuillez noter que ce n'est le cas que pour les variables et les tableaux de variables, et non pour les méthodes, etc.

user3569257
la source
-4

Essayez simplement d'importer les fonctions nécessaires à partir de main.py? Alors,

from main import SomeFunction

Il se peut que vous ayez nommé une fonction dans batch.py ​​de la même manière que dans main.py, et lorsque vous importez main.py, le programme exécute la fonction main.py au lieu de la fonction batch.py; faire ce qui précède devrait résoudre ce problème. J'espère.

Dave Lewis
la source
Au moins sur Windows, ce n'est pas le cas.
Martín Coll
2
import mainN'importe PAS tout de main dans l'espace de noms actuel. Il n'ajoute qu'un seul mainsymbole dans l'espace de noms actuel, donc les collisions ne peuvent pas se produire.
remram