Quelle est la meilleure façon d'appeler un script à partir d'un autre script?

308

J'ai un script nommé test1.py qui n'est pas dans un module. Il a juste du code qui devrait s'exécuter lorsque le script lui-même est exécuté. Il n'y a pas de fonctions, classes, méthodes, etc. J'ai un autre script qui fonctionne comme un service. Je veux appeler test1.py à partir du script exécuté en tant que service.

Par exemple:

Fichier test1.py

print "I am a test"
print "see! I do nothing productive."

File service.py

# Lots of stuff here
test1.py # do whatever is in test1.py

Je connais une méthode qui ouvre le fichier, lit le contenu et l'évalue. Je suppose qu'il existe une meilleure façon de procéder. Ou du moins je l'espère.

Josh Smeaton
la source
42
La meilleure façon est d'écrire des méthodes et des classes et de les utiliser
Aamir
3
Personne n'a encore posté de runpy.run_moduleréponse?!
Aran-Fey

Réponses:

279

La façon habituelle de procéder est quelque chose comme ce qui suit.

test1.py

def some_func():
    print 'in test 1, unproductive'

if __name__ == '__main__':
    # test1.py executed as script
    # do something
    some_func()

service.py

import test1

def service_func():
    print 'service func'

if __name__ == '__main__':
    # service.py executed as script
    # do something
    service_func()
    test1.some_func()
ars
la source
44
Et si test1.pyse trouve dans un répertoire éloigné?
Evgeni Sergeev
3
@EvgeniSergeev Voir stackoverflow.com/questions/67631/…
Evgeni Sergeev
18
Cela ne répond pas vraiment à la question, n'est-ce pas? Vous n'exécutez pas l'intégralité du script, vous exécutez certaines fonctions à partir du script que vous importez.
gented
2
@GennaroTedesco: Vous vous trompez. Le import test1in service.pyexécute en effet tout le script (qui ne définit que some_func()puisque le __name__ == '__main__'sera Falsedans ce cas). Cela ressemble à tout ce que l'OP veut faire. Cette réponse va au-delà de cela, mais répond certainement à la question - et puis à certains.
martineau
2
Si, par exemple, test1.pyne contenait pas la définition de la fonction some_func()(mais plutôt juste quelques lignes de code, par exemple print("hello")) alors votre code ne fonctionnerait pas. Dans cet exemple particulier, cela fonctionne parce que vous importez essentiellement une fonction externe que vous rappelez ensuite.
gented
144

Ceci est possible dans Python 2 en utilisant

execfile("test2.py")

Consultez la documentation pour la gestion des espaces de noms, si cela est important dans votre cas.

En Python 3, cela est possible en utilisant (grâce à @fantastory)

exec(open("test2.py").read())

Cependant, vous devriez envisager d'utiliser une approche différente; votre idée (d'après ce que je peux voir) ne semble pas très propre.

balpha
la source
9
directement ce dont j'ai besoin en python 32 c'est exec (open ('test2.py'). read ())
fantastory
8
Cette approche exécute les scripts dans l'espace de noms appelant. :)
dmvianna
6
pour passer des arguments de ligne de commande au script, vous pouvez modifier la sys.argvliste.
jfs
1
Traitement plus complet sur les équivalents Python 3: stackoverflow.com/questions/436198/…
John Y
2
Cela n'accepte pas d'arguments (à transmettre au fichier PY)!
Apostolos
71

Autrement:

Fichier test1.py:

print "test1.py"

Fichier service.py:

import subprocess

subprocess.call("test1.py", shell=True)

L'avantage de cette méthode est que vous n'avez pas à modifier un script Python existant pour mettre tout son code dans un sous-programme.

Documentation: Python 2 , Python 3

Dick Goodwin
la source
8
Je devais utiliser subprocess.call("./test1.py", shell=True)pour le faire fonctionner
asmaier
5
Ne pas utiliser shell=Truesauf si cela est nécessaire.
Piotr Dobrogost
2
@PiotrDobrogost - Pourriez-vous préciser quelles situations le rendraient nécessaire?
sancho.s ReinstateMonicaCellio
8
Cela ne fonctionnera pas sur un Unix typique où le répertoire actuel n'est pas dans PATH. test1.pydoit être exécutable et avoir la ligne shebang ( #!/usr/bin/env python) et vous devez spécifier le chemin complet ou vous devez fournir l'exécutable vous-même: call([sys.executable, os.path.join(get_script_dir(), 'test1.py')])get_script_dir()est défini ici .
jfs
5
Ou subprocess.call(['python', 'test1.py']).
Big McLargeHuge
21

Si vous voulez que test1.py reste exécutable avec les mêmes fonctionnalités que lorsqu'il est appelé dans service.py, faites quelque chose comme:

test1.py

def main():
    print "I am a test"
    print "see! I do nothing productive."

if __name__ == "__main__":
    main()

service.py

import test1
# lots of stuff here
test1.main() # do whatever is in test1.py
Michael Schneider
la source
3
Et si vous avez des paramètres d'exécution?
Gabriel Fair
13
import os

os.system("python myOtherScript.py arg1 arg2 arg3")  

En utilisant os, vous pouvez appeler directement votre terminal. Si vous voulez être encore plus précis, vous pouvez concaténer votre chaîne d'entrée avec des variables locales, c'est-à-dire.

command = 'python myOtherScript.py ' + sys.argv[1] + ' ' + sys.argv[2]
os.system(command)
Alex Mapley
la source
les appels à os.systemdoivent être évités, vous pouvez faire de même avec n'importe quelle classe dePopen, Call,
user1767754
À partir de la documentation Python : Le module de sous-processus fournit des fonctionnalités plus puissantes pour générer de nouveaux processus et récupérer leurs résultats; l'utilisation de ce module est préférable à l'utilisation de cette fonction.
Big McLargeHuge
12

Vous ne devriez pas faire ça. Au lieu de cela, faites:

test1.py:

 def print_test():
      print "I am a test"
      print "see! I do nothing productive."

service.py

#near the top
from test1 import print_test
#lots of stuff here
print_test()
thedz
la source
1
lorsque vous importez test1, comment sait-il où se trouve le fichier? doit-il être dans le même répertoire? Et si ce n'est pas le cas?
NULL.Dude
8

Utilisation import test1 pour la 1ère utilisation - il exécutera le script. Pour les appels ultérieurs, traitez le script comme un module importé et appelez la reload(test1)méthode.

Quand reload(module)est exécuté:

  • Le code des modules Python est recompilé et le code au niveau du module réexécuté , définissant un nouvel ensemble d'objets qui sont liés aux noms dans le dictionnaire du module. La fonction init des modules d'extension n'est pas appelée

Une simple vérification de sys.modulespeut être utilisée pour appeler l'action appropriée. Pour continuer à faire référence au nom du script sous forme de chaîne ( 'test1'), utilisez le module intégré ' import ()' .

import sys
if sys.modules.has_key['test1']:
    reload(sys.modules['test1'])
else:
    __import__('test1')
gimel
la source
3
reloadest parti en Python 3.
Piotr Dobrogost
1
importer un module n'est pas équivalent à l'exécuter, par exemple, pensez à if __name__ == "__main__":guard. Il pourrait y avoir d'autres différences plus subtiles. Ne laissez pas de code arbitraire au niveau global. Mettez-le dans une fonction et appelez-le après l'importation comme suggéré dans la réponse acceptée à la place
jfs
5

Je préfère runpy :

#!/usr/bin/env python
# coding: utf-8

import runpy

runpy.run_path(path_name='script-01.py')
runpy.run_path(path_name='script-02.py')
runpy.run_path(path_name='script-03.py')
Flavio
la source
3

Pourquoi ne pas simplement importer test1? Chaque script python est un module. Une meilleure façon serait d'avoir une fonction par exemple main / run dans test1.py, import test1 et run test1.main (). Ou vous pouvez exécuter test1.py en tant que sous-processus.

Anurag Uniyal
la source
3

Comme cela a déjà été mentionné, runpyest un bon moyen d'exécuter d'autres scripts ou modules à partir du script actuel.

Soit dit en passant, il est assez courant qu'un traceur ou un débogueur le fasse, et dans de telles circonstances, des méthodes telles que l'importation directe du fichier ou l'exécution du fichier dans un sous-processus ne fonctionnent généralement pas.

Il doit également être utilisé execpour exécuter le code. Vous devez fournir correctement run_globalspour éviter une erreur d'importation ou d'autres problèmes. Reportez-vous à runpy._run_codepour plus de détails.

Chao Chen
la source
0

Ceci est un exemple avec la subprocessbibliothèque:

import subprocess

python_version = '3'
path_to_run = './'
py_name = '__main__.py'

# args = [f"python{python_version}", f"{path_to_run}{py_name}"]  # Avaible in python3
args = ["python{}".format(python_version), "{}{}".format(path_to_run, py_name)]

res = subprocess.Popen(args, stdout=subprocess.PIPE)
output, error_ = res.communicate()

if not error_:
    print(output)
else:
    print(error_)
Benyamin Jafari
la source
1
L'exécution de Python en tant que sous-processus de Python n'est presque jamais la bonne solution. Si vous optez pour un sous-processus, vous devez éviter à Popenmoins que les fonctions de niveau supérieur ne puissent vraiment pas faire ce que vous voulez. Dans ce cas, check_callou runferait tout ce dont vous avez besoin et plus, avec beaucoup moins de plomberie dans votre propre code.
tripleee
0

Ce processus est quelque peu anti-orthodoxe, mais fonctionnerait dans toutes les versions de python,

Supposons que vous vouliez exécuter un script nommé 'recommend.py' à l'intérieur d'une condition 'if', puis utilisez,

if condition:
       import recommend

La technique est différente, mais fonctionne!

Ashwin Balani
la source