¿Cuál es la mejor manera de llamar un script desde otro script?

307

Tengo un script llamado test1.py que no está en un módulo. Simplemente tiene código que debe ejecutarse cuando se ejecuta el script en sí. No hay funciones, clases, métodos, etc. Tengo otro script que se ejecuta como un servicio. Quiero llamar a test1.py desde el script que se ejecuta como un servicio.

Por ejemplo:

Archivo test1.py

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

Archivo service.py

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

Conozco un método que es abrir el archivo, leer el contenido y básicamente evaluarlo. Supongo que hay una mejor manera de hacer esto. O al menos eso espero.

Josh Smeaton
fuente
42
La mejor manera es escribir métodos y clases y usarlos
Aamir
3
¿Nadie ha publicado una runpy.run_modulerespuesta todavía?
Aran-Fey

Respuestas:

279

La forma habitual de hacer esto es algo como lo siguiente.

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
fuente
44
¿Qué pasa si test1.pyse encuentra en un directorio lejano?
Evgeni Sergeev
3
@EvgeniSergeev Ver stackoverflow.com/questions/67631/…
Evgeni Sergeev
18
Sin embargo, esto realmente no responde la pregunta, ¿verdad? No está ejecutando todo el script, está ejecutando algunas funciones desde el script que importa.
Gented
2
@GennaroTedesco: Estás equivocado. De hecho, import test1in service.pyejecuta todo el script (que solo define, some_func()ya __name__ == '__main__'que será Falseen ese caso). Eso suena como todo lo que el OP quiere hacer. Esta respuesta va más allá de eso, pero definitivamente responde la pregunta, y algo más.
Martineau
2
Si, por ejemplo, test1.pyno contiene la definición de la función some_func()(sino solo algunas líneas de código, por ejemplo print("hello")), entonces su código no funcionaría. En este ejemplo en particular, funciona porque esencialmente está importando una función externa a la que luego está volviendo a llamar.
Gented
144

Esto es posible en Python 2 usando

execfile("test2.py")

Consulte la documentación para el manejo de espacios de nombres, si es importante en su caso.

En Python 3, esto es posible usando (gracias a @fantastory)

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

Sin embargo, debe considerar usar un enfoque diferente; Su idea (por lo que puedo ver) no se ve muy limpia.

balpha
fuente
99
directamente lo que necesito en python 32 es exec (open ('test2.py'). read ())
fantastory
8
Este enfoque ejecuta los scripts dentro del espacio de nombres de llamada. :)
dmvianna
66
para pasar argumentos de línea de comandos al script, puede editar la sys.argvlista.
jfs
1
Tratamiento más completo en equivalentes de Python 3: stackoverflow.com/questions/436198/…
John Y
2
¡Esto no acepta argumentos (para pasar al archivo PY)!
Apostolos
70

De otra manera:

Archivo test1.py:

print "test1.py"

Archivo service.py:

import subprocess

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

La ventaja de este método es que no tiene que editar un script Python existente para poner todo su código en una subrutina.

Documentación: Python 2 , Python 3

Dick Goodwin
fuente
77
Tuve que usar subprocess.call("./test1.py", shell=True)para hacerlo funcionar
asmaier
55
No lo use a shell=Truemenos que sea necesario.
Piotr Dobrogost
2
@PiotrDobrogost: ¿podría especificar qué situaciones lo harían necesario?
sancho.s ReinstateMonicaCellio
77
No funcionará en un Unix típico donde el directorio actual no está en RUTA. test1.pydebe ser ejecutable y tener la línea shebang ( #!/usr/bin/env python) y debe especificar la ruta completa o debe proporcionar el ejecutable usted mismo: call([sys.executable, os.path.join(get_script_dir(), 'test1.py')])dónde get_script_dir()se define aquí .
jfs
55
O subprocess.call(['python', 'test1.py']).
Big McLargeHuge
21

Si desea que test1.py siga siendo ejecutable con la misma funcionalidad que cuando se llama dentro de service.py, haga algo como:

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
fuente
3
¿Qué pasa si tiene parámetros de tiempo de ejecución?
Gabriel Fair
13
import os

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

Usando el sistema operativo puede hacer llamadas directamente a su terminal. Si desea ser aún más específico, puede concatenar su cadena de entrada con variables locales, es decir.

command = 'python myOtherScript.py ' + sys.argv[1] + ' ' + sys.argv[2]
os.system(command)
Alex Mapley
fuente
os.systemdeben evitarse las llamadas a , puede hacer lo mismo con cualquier clase dePopen, Call,
user1767754
De la documentación de Python : el módulo de subprocesos proporciona instalaciones más potentes para generar nuevos procesos y recuperar sus resultados; usar ese módulo es preferible a usar esta función.
Big McLargeHuge
12

No deberías estar haciendo esto. En cambio, haz:

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
fuente
1
cuando importa test1, ¿cómo sabe dónde está el archivo? ¿tiene que estar en el mismo directorio? ¿Y si no es así?
NULL.Dude
8

Uso import test1para el primer uso: ejecutará el script. Para invocaciones posteriores, trate el script como un módulo importado y llame al reload(test1)método.

Cuando reload(module)se ejecuta:

  • El código de los módulos de Python se vuelve a compilar y el código de nivel de módulo se vuelve a ejecutar , definiendo un nuevo conjunto de objetos que están vinculados a nombres en el diccionario del módulo. La función init de los módulos de extensión no se llama

Se sys.modulespuede usar una simple verificación de para invocar la acción apropiada. Para seguir refiriéndose al nombre del script como una cadena ( 'test1'), use la función incorporada ' import ()' .

import sys
if sys.modules.has_key['test1']:
    reload(sys.modules['test1'])
else:
    __import__('test1')
gimel
fuente
3
reloadse ha ido en Python 3.
Piotr Dobrogost
1
importar un módulo no es equivalente a ejecutarlo, por ejemplo, considere if __name__ == "__main__":guardar. Podría haber otras diferencias más sutiles. No deje código arbitrario a nivel global. Póngalo en una función y
llámelo
5

Prefiero 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
fuente
3

¿Por qué no solo importar test1? Cada script de Python es un módulo. Una mejor manera sería tener una función, por ejemplo, main / run en test1.py, import test1 y run test1.main (). O puede ejecutar test1.py como un subproceso.

Anurag Uniyal
fuente
3

Como ya se mencionó, runpyes una buena manera de ejecutar otros scripts o módulos desde el script actual.

Por cierto, es bastante común que un rastreador o depurador haga esto, y en tales circunstancias, los métodos como importar el archivo directamente o ejecutar el archivo en un subproceso generalmente no funcionan.

También necesita atención para usar execel código. Debe proporcionar la información adecuada run_globalspara evitar errores de importación u otros problemas. Consulte runpy._run_codepara más detalles.

Chao Chen
fuente
0

Este es un ejemplo con la subprocessbiblioteca:

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
fuente
1
Ejecutar Python como un subproceso de Python casi nunca es la solución correcta. Si va con un subproceso, debe evitarlo a Popenmenos que las funciones de nivel superior realmente no puedan hacer lo que desea. En este caso, check_callo runharía todo lo que necesita y más, con sustancialmente menos plomería en su propio código.
tripleee
0

Este proceso no es ortodoxo, pero funcionaría en todas las versiones de Python,

Suponga que desea ejecutar un script llamado 'recomendar.py' dentro de una condición 'si', luego use,

if condition:
       import recommend

La técnica es diferente, ¡pero funciona!

Ashwin Balani
fuente