web-dev-qa-db-fra.com

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

Je souhaite exécuter un script Python à partir d'un autre script Python. Je souhaite transmettre des variables comme si je utilisais la ligne de commande.

Par exemple, je lancerais mon premier script qui parcourrait une liste de valeurs (0,1,2,3) et les transmettrait au deuxième script script2.py 0 puis script2.py 1, etc.

J'ai trouvé question de débordement de pile 1186789 qui est une question similaire, mais la réponse de ars appelle une fonction, où, comme je veux exécuter le script entier, 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 à titre de test:

execfile("script2.py 1")

Mais ce n'est pas accepter les variables correctement. Lorsque j'imprime le sys.argv dans script2.py, il s'agit de l'appel de commande d'origine du premier script "['C:\script1.py'].

Je ne veux pas vraiment changer le script d'origine (c'est-à-dire script2.py dans mon exemple) car je ne le possède pas.

Je pense qu'il doit y avoir un moyen de le faire; Je suis juste confus comment vous le faites.

278
Gern Blanston

Essayez d’utiliser os.system :

_os.system("script2.py 1")
_

execfile est différent car il est conçu pour exécuter une séquence d'instructions Python dans le contexte d'exécution actuel . C'est pourquoi _sys.argv_ n'a pas changé pour vous.

286
Greg Hewgill

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

import script1

Dans un monde idéal, vous pourrez 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. Pour ce faire, utilisez un gestionnaire de contexte afin d’éviter toute modification permanente.

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 cela est préférable à la transmission de toutes vos données au système d'exploitation et inversement; c'est juste idiot.

94
Katriel

Idéalement, le script Python que vous voulez exécuter sera configuré avec le code suivant:

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


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

En d'autres termes, if le module est appelé à partir de la ligne de commande, il analyse les options de la ligne de commande, puis appelle une autre fonction, main(), pour effectuer le travail proprement dit. (Les arguments réels varieront et l'analyse sera peut-être plus complexe.)

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

os.system fonctionnera, mais c’est la façon la plus simple de le faire, car vous démarrez un tout nouveau processus d’interprète Python à chaque fois sans raisin.

87
kindall

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.

40
Chris Adams

Je pense que la bonne pratique peut être quelque chose comme ça;

import subprocess
cmd = 'python script.py'

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, Shell=True)
out, err = p.communicate() 
result = out.split('\n')
for lin in result:
    if not lin.startswith('#'):
        print(lin)

selon la documentation Le module de sous-processus vous permet de générer de nouveaux processus, de vous connecter à leurs canaux d'entrée/sortie/d'erreur et d'obtenir leurs codes de retour. Ce module vise à remplacer plusieurs modules et fonctions plus anciens:

os.system
os.spawn*
os.popen*
popen2.*
commands.*

Utilisez communication () plutôt que .stdin.write, .stdout.read ou .stderr.read pour éviter les blocages dus à l'un des autres tampons de tube du système d'exploitation remplissant et bloquant le processus enfant. Lire ici

35
Medhat
import subprocess
subprocess.call(" python script2.py 1", Shell=True)
26
Nikos

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

3
nmichaels