Qual è il modo migliore per chiamare uno script da un altro script?


307

Ho uno script chiamato test1.py che non è in un modulo. Ha solo codice che dovrebbe essere eseguito quando viene eseguito lo script stesso. Non ci sono funzioni, classi, metodi, ecc. Ho un altro script che funziona come un servizio. Voglio chiamare test1.py dallo script in esecuzione come servizio.

Per esempio:

File 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

Sono a conoscenza di un metodo che sta aprendo il file, leggendo il contenuto e sostanzialmente valutandolo. Suppongo che ci sia un modo migliore per farlo. O almeno lo spero.


42
Il modo migliore è scrivere metodi e classi e usarli
Aamir,


3
Nessuno ha runpy.run_moduleancora pubblicato una risposta ?!
Aran-Fey

Risposte:


279

Il solito modo per farlo è qualcosa di simile al seguente.

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

44
Cosa succede se test1.pysi trova in una directory lontana?
Evgeni Sergeev,


18
Questo in realtà non risponde alla domanda, vero? Non stai eseguendo l'intero script, stai eseguendo alcune funzioni all'interno dello script che importi.
Gented

2
@GennaroTerman: ti sbagli. La import test1in service.pyeffettivamente eseguire l' intera edizione (che definisce soltanto some_func()poiché __name__ == '__main__'sarà Falsein questo caso). Sembra che tutto ciò che l'OP vuole fare. Questa risposta va oltre, ma sicuramente risponde alla domanda - e poi alcune.
martineau,

2
Se, diciamo, test1.pynon contenesse la definizione della funzione some_func()(ma piuttosto solo alcune righe di codice, ad esempio print("hello")), il tuo codice non funzionerebbe. In questo esempio particolare funziona perché stai essenzialmente importando una funzione esterna che in seguito stai richiamando.
ricevuto il

144

Questo è possibile in Python 2 usando

execfile("test2.py")

Consulta la documentazione per la gestione degli spazi dei nomi, se importante nel tuo caso.

In Python 3, questo è possibile usando (grazie a @fantastory)

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

Tuttavia, dovresti considerare l'utilizzo di un approccio diverso; la tua idea (da quello che posso vedere) non sembra molto pulita.


9
direttamente quello di cui ho bisogno in Python 32 è exec (open ('test2.py'). read ())
fantastory

8
Questo approccio esegue gli script all'interno dello spazio dei nomi chiamante. :)
dmvianna,

6
per passare argomenti della riga di comando allo script, è possibile modificare l' sys.argvelenco.
jfs

1
Trattamento più completo sugli equivalenti di Python 3: stackoverflow.com/questions/436198/…
John Y

2
Questo non accetta argomenti (da passare al file PY)!
Apostolos,

70

Un altro modo:

File test1.py:

print "test1.py"

File service.py:

import subprocess

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

Il vantaggio di questo metodo è che non è necessario modificare uno script Python esistente per mettere tutto il suo codice in una subroutine.

Documentazione: Python 2 , Python 3


7
Ho dovuto usare subprocess.call("./test1.py", shell=True)per farlo funzionare
asmaier

5
Non utilizzare a shell=Truemeno che non sia necessario.
Piotr Dobrogost,

2
@PiotrDobrogost - Potresti specificare quali situazioni lo renderebbero necessario?
sancho.s ReinstateMonicaCellio il

7
Non funzionerà su un tipico Unix in cui la directory corrente non si trova in PERCORSO. test1.pydovrebbe essere eseguibile e avere la riga shebang ( #!/usr/bin/env python) e dovresti specificare il percorso completo o devi fornire tu stesso l'eseguibile: call([sys.executable, os.path.join(get_script_dir(), 'test1.py')])dove get_script_dir()è definito qui .
jfs

5
Or subprocess.call(['python', 'test1.py']).
Big McLarge: enorme

21

Se vuoi che test1.py rimanga eseguibile con le stesse funzionalità di quando viene chiamato all'interno di service.py, fai qualcosa del tipo:

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

3
Cosa succede se si hanno parametri di runtime?
Gabriel Fair,

13
import os

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

Usando os è possibile effettuare chiamate direttamente al proprio terminale. Se vuoi essere ancora più specifico, puoi concatenare la stringa di input con variabili locali, ad es.

command = 'python myOtherScript.py ' + sys.argv[1] + ' ' + sys.argv[2]
os.system(command)

le chiamate a os.systemdovrebbero essere evitate, puoi fare lo stesso con qualsiasi classe daPopen, Call,
user1767754

Dalla documentazione di Python : il modulo di sottoprocesso fornisce servizi più potenti per generare nuovi processi e recuperare i loro risultati; usare quel modulo è preferibile usare questa funzione.
Big McLarge, enorme

12

Non dovresti farlo. Invece, fai:

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

1
quando importi test1 come fa a sapere dove si trova il file? deve essere nella stessa directory? e se non lo fosse?
NULL.Dude

8

Usa import test1per il primo utilizzo: eseguirà lo script. Per invocazioni successive, considera lo script come un modulo importato e chiama il reload(test1)metodo.

Quando reload(module)viene eseguito:

  • Il codice dei moduli Python viene ricompilato e il codice a livello di modulo viene rieseguito , definendo un nuovo set di oggetti che sono associati ai nomi nel dizionario del modulo. La funzione init dei moduli di estensione non viene chiamata

Un semplice controllo di sys.modulespuò essere utilizzato per invocare l'azione appropriata. Per continuare a fare riferimento al nome dello script come stringa ( 'test1'), utilizzare il comando incorporato " import ()" .

import sys
if sys.modules.has_key['test1']:
    reload(sys.modules['test1'])
else:
    __import__('test1')

3
reloadè andato in Python 3.
Piotr Dobrogost,

1
importare un modulo non equivale a eseguirlo, ad esempio, considera if __name__ == "__main__":guard. Potrebbero esserci altre differenze più sottili. Non lasciare codice arbitrario a livello globale. Mettetelo in una funzione e chiamarlo dopo l'importazione come suggerito nella risposta accettata invece
JFS

5

Preferisco 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')

3

Perché non importare solo test1? Ogni script Python è un modulo. Un modo migliore sarebbe quello di avere una funzione, ad esempio main / run in test1.py, importare test1 ed eseguire test1.main (). Oppure puoi eseguire test1.py come sottoprocesso.


3

Come già accennato, runpyè un buon modo per eseguire altri script o moduli dallo script corrente.

A proposito, è abbastanza comune per un tracciante o debugger farlo, e in tali circostanze metodi come l'importazione del file direttamente o l'esecuzione del file in un sottoprocesso di solito non funzionano.

Richiede anche attenzione da usare execper eseguire il codice. Devi fornire le informazioni appropriate run_globalsper evitare errori di importazione o altri problemi. Fare riferimento runpy._run_codeper i dettagli.


0

Questo è un esempio con la subprocesslibreria:

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_)

1
Eseguire Python come sottoprocesso di Python non è quasi mai la soluzione corretta. Se vai con un sottoprocesso, dovresti evitare a Popenmeno che le funzioni di livello superiore non possano davvero fare quello che vuoi. In questo caso, check_callo runfarebbe tutto ciò di cui hai bisogno e di più, con sostanzialmente meno impianti idraulici nel tuo codice.
Tripleee

0

Questo processo è in qualche modo non ortodosso, ma funzionerebbe su tutte le versioni di Python,

Supponiamo di voler eseguire uno script chiamato 'recommend.py' all'interno di una condizione 'if', quindi utilizzare,

if condition:
       import recommend

La tecnica è diversa, ma funziona!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.