376 votes

Exécuter un script Python à partir d'un autre script Python, en passant des arguments.

Je veux exécuter un script Python à partir d'un autre script Python. Je veux passer des variables comme je le ferais en utilisant la ligne de commande.

Par exemple, je lancerais mon premier script qui itérerait à travers une liste de valeurs (0,1,2,3) et passerait celles-ci au 2ème script. script2.py 0 puis script2.py 1 etc.

J'ai trouvé Question Stack Overflow 1186789 qui est une question similaire, mais la réponse de ars appelle une fonction, alors que je veux exécuter l'ensemble du script, pas seulement une fonction, et la réponse de balpha appelle le script mais sans arguments. J'ai changé cela en quelque chose comme le ci-dessous comme un test :

execfile("script2.py 1")

Mais il n'accepte pas les variables correctement. Lorsque j'imprime le sys.argv dans script2.py c'est l'appel de la commande originale à la première script "[']. C:\script1.py '].

Je ne veux pas vraiment modifier le script original (c'est-à-dire script2.py dans mon exemple) puisque je ne le possède pas.

Je me dis qu'il doit y avoir un moyen de le faire, mais je ne sais pas comment vous vous y prenez.

1 votes

Si os.system n'est pas assez puissant pour vous, il y a le module de sous-processus .

1 votes

La question est de savoir si vous connaissez le nom du script (alors importez-le) ou si vous ne connaissez pas le nom du script au moment de la programmation (alors utilisez subprocess.call). Dans le second cas, cette question ne serait pas non plus un doublon. Comme la question n'est pas claire, elle n'est pas non plus vraiment bonne.

0 votes

@Trilarion : faux. Vous pouvez importer un module python même si son nom est généré au moment de l'exécution.

366voto

Greg Hewgill Points 356191

Essayez d'utiliser os.system :

os.system("script2.py 1")

execfile est différent parce qu'il est conçu pour exécuter une séquence d'instructions Python dans l'environnement de travail de l'utilisateur. actuel contexte d'exécution. C'est pourquoi sys.argv n'a pas changé pour vous.

59 votes

Je pense qu'il est généralement préférable d'utiliser subprocess.Popen sur os.system : docs.python.org/library/subprocess.html#replacing-os-system .

11 votes

Oui, c'est pour ça que l'aide os.system dit. Cependant, pour les utilisations simples os.system est la façon la plus simple de faire le travail. Cela dépend de vos besoins, bien sûr.

2 votes

Vous pouvez également utiliser subprocess.check_call().

121voto

katrielalex Points 40655

C'est intrinsèquement la mauvaise chose à faire. Si vous exécutez un script Python à partir d'un autre script Python, vous devez communiquer par Python plutôt que par le système d'exploitation :

import script1

Dans un monde idéal, vous serez en mesure d'appeler une fonction à l'intérieur de script1 directement :

for i in range(whatever):
    script1.some_function(i)

Si nécessaire, vous pouvez pirater sys.argv . Il existe un moyen astucieux de le faire en utilisant un gestionnaire de contexte pour s'assurer que vous ne faites pas de changements permanents.

import contextlib
@contextlib.contextmanager
def redirect_argv(num):
    sys._argv = sys.argv[:]
    sys.argv=[str(num)]
    yield
    sys.argv = sys._argv

with redirect_argv(1):
    print(sys.argv)

Je pense que c'est préférable à la transmission de toutes vos données au système d'exploitation et vice-versa ; c'est tout simplement stupide.

20 votes

C'est peut-être la "mauvaise" chose à faire mais que se passe-t-il si le script que vous devez référencer n'a pas de main ou de functions.... un import exécuterait le script au moment de l'import, ce qui n'est probablement pas ce que vous voulez (et vous ne voulez pas le refactoriser parce que les gens utilisent aussi ce script tel quel). os/subprocess pourrait gérer un tel cas

0 votes

C'est vrai... mais c'est une autre question IMO !

4 votes

Cela ne va-t-il pas échouer pour les scripts multithreads ?

109voto

kindall Points 60645

Idéalement, le script Python que vous voulez exécuter sera configuré avec un code comme celui-ci vers la fin :

def main(arg1, arg2, etc):
    # do whatever the script does

if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2], sys.argv[3])

En d'autres termes, si le module est appelé depuis la ligne de commande, il analyse les options de la ligne de commande et appelle ensuite une autre fonction, main() pour faire le travail réel. (Les arguments réels varieront, et l'analyse syntaxique peut être plus impliquée).

Si vous voulez appeler un tel script à partir d'un autre script Python, cependant, vous pouvez simplement import et l'appeler modulename.main() directement, plutôt que de passer par le système d'exploitation.

os.system fonctionnera, mais c'est la manière la plus détournée (lisez "lente") de le faire, car vous démarrez un tout nouveau processus d'interprétation Python à chaque fois pour aucun raisin.

14 votes

Re : "pas de raisin sec". Il ne s'agit pas d'une erreur. Cependant, il était intéressant de voir combien de temps cela prendrait à quelqu'un qui n'est pas familier avec l'utilisation de l'ordinateur. Futurama pour le " corriger " dans une question aléatoire de Stack Overflow : deux ans et trois mois :-)

0 votes

J'ai ri de "no raisin" simplement parce que c'était une faute de frappe ridicule, puis j'ai vu votre commentaire et trouvé un clip sur YouTube. Encore plus drôle.

0 votes

J'avais un script sans main, mais j'ai pu introduire comme ça : 1. Séparer les défs de fonction et les déclarations autonomes 2. Faire le parsing des arguments sous le "if nom ..." section 3. indenter le reste des déclarations sous def main(...) et faire en sorte que cette logique opère sur les paramètres de la méthode. Ensuite, j'ai pu appeler la méthode principale à partir d'un autre script (ex : Un test unitaire)

45voto

ChrisAdams Points 401

Module de sous-processus :
http://docs.python.org/dev/library/subprocess.html#using-the-subprocess-module

import subprocess
subprocess.Popen("script2.py 1", shell=True)

Avec cela, vous pouvez également rediriger stdin, stdout et stderr.

12 votes

Ne pas utiliser shell=True sauf si nécessaire.

0 votes

@PiotrDobrogost pouvez-vous nous en dire plus ? Edit : Pour les curieux, voici une explication du pourquoi : stackoverflow.com/questions/3172470/

33voto

Nikos Points 31
import subprocess
subprocess.call(" python script2.py 1", shell=True)

23 votes

Vous pouvez développer votre réponse pour expliquer pourquoi cette option est meilleure que certaines des autres réponses présentées ici.

2 votes

Comment passer un argument mais pas sous forme de chaîne, par exemple une liste ? Y a-t-il une autre option que de passer chaque élément séparément ?

1 votes

N'utilisez shell=True que si cela est nécessaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X