2010-09-23 21 views
217

Quiero ejecutar un script de Python desde otro script de Python. Quiero pasar variables como lo haría usando la línea de comando.Ejecutar un script de python desde otro script de python, pasando args

Por ejemplo, me gustaría dirigir mi primer guión que iterar a través de una lista de valores (0,1,2,3) y pasar los al segundo guión script2.py 0 continuación script2.py 1, etc.

me encontré con SO 1186789 que es una pregunta similar pero la respuesta de ars llama a una función, donde como quiero ejecutar todo el script no es solo una función, y la respuesta de balpha llama al script pero sin argumentos. Lo alteré a algo como el siguiente como una prueba:

execfile("script2.py 1") 

Pero no acepta las variables correctamente. Cuando imprimo sys.argv en script2.py, es la llamada original al primer script "['C: \ script1.py'].

Realmente no quiero cambiar el script original (es decir, script2. .. py en mi ejemplo) ya que no poseo

calculo tiene que haber una manera de hacer esto, estoy confundido cómo lo hace

+0

La pregunta es si conoce el nombre del script (luego lo importa) o si no conoce el nombre del script en tiempo de programación (luego use subprocess.call). En el segundo caso, esta pregunta tampoco sería un duplicado. Debido a que la pregunta no lo deja claro, tampoco es realmente buena. – Trilarion

+0

@Trilarion: mal. Puede importar un módulo de python incluso si su nombre se genera en tiempo de ejecución. – jfs

+0

@ J.F.Sebastian Bien. Como observación adicional: de esta manera, esta respuesta no está bien cubierta por ninguna respuesta aquí o en la pregunta vinculada, excepto en parte en http://stackoverflow.com/a/1186840/1536976. – Trilarion

Respuesta

238

Intente utilizar os.system:

os.system("script2.py 1") 

execfile es diferente porque está diseñado para ejecutar una secuencia nce de instrucciones Python en el contexto de ejecución actual. Es por eso que sys.argv no cambió para usted.

+36

Creo que generalmente es preferible usar 'subprocess.Popen' sobre' os.system': http://docs.python.org/library/subprocess.html#replacing-os-system. – katrielalex

+9

Sí, eso es lo que dice la ayuda para 'os.system'. Sin embargo, para usos simples 'os.system' es la forma más sencilla de hacer el trabajo. Depende de tus necesidades, por supuesto. –

+2

También puede usar subprocess.check_call(). – MarioVilas

81

Esto es inherentemente lo que no debe hacer. Si está ejecutando un script de Python desde otro script Python, debe comunicarse a través de Python en lugar de a través del sistema operativo:

import script1 

En un mundo ideal, usted será capaz de llamar a una función dentro de script1 directamente:

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

Si es necesario, puede hackear sys.argv. Hay una buena manera de hacerlo utilizando un administrador de contexto para garantizar que no realice ningún cambio 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) 

Creo que esto es preferible a pasar todos sus datos al sistema operativo y viceversa; eso es tonto.

+9

Podría ser lo "incorrecto" pero, ¿qué pasa si el script que necesita referencia no tiene main o funciones ... una importación ejecutaría el script en el momento de la importación, que probablemente no es lo que desea (y no desea refactorizar porque las personas también están usando esa secuencia de comandos como está). os/subprocess podría ocuparse de tal caso –

+0

Verdadero ... pero esa es una pregunta diferente ¡OMI! – katrielalex

+4

¿No fallarán los scripts de subprocesos múltiples? – MarioVilas

70

Idealmente, la secuencia de comandos de Python que desea ejecutar será creado con código como este cerca del final:

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


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

En otras palabras, si el módulo se llama desde la línea de comandos, se realiza un análisis sintáctico las opciones de línea de comando y luego llama a otra función, main(), para hacer el trabajo real. (Los argumentos reales pueden variar, y el análisis puede ser más complicado.)

Si desea llamar a un script desde otro script en Python, sin embargo, puede simplemente import y llame modulename.main() directamente, en lugar de ir a través de la sistema operativo.

os.system funcionará, pero es la manera indirecta (leer "lento") de hacerlo, ya que está comenzando un nuevo proceso de intérprete de Python cada vez sin pasas.

+9

Re:" sin pasas ". Esto no es un error. Sin embargo, fue interesante ver cuánto tiempo tardaría alguien que no estaba familiarizado con * Futurama * en "corregirlo" en una pregunta aleatoria de Desbordamiento de pila: dos años y tres meses. :-) – kindall

+0

Me reí de "no pasas" simplemente porque era un error tipográfico ridículo, luego vi tu comentario y encontré un clip en YouTube. Aún más gracioso. – armani

+0

Tenía un script sin main, pero pude introducirlo de la siguiente manera: 1. Definiciones de funciones separadas y declaraciones independientes 2. Analice el argumento bajo la sección "if __name __ ..." 3. sangrar el resto de sentencias en def main (...) y tienen esa lógica operando en los parámetros del método. Luego pude llamar al método principal desde otro script (por ejemplo, una prueba de unidad) –

21
import subprocess 
subprocess.call(" python script2.py 1", shell=True) 
+14

Es posible que desee ampliar su respuesta para explicar por qué esta es una opción mejor que algunas de las otras respuestas presentadas aquí. –

+1

Cómo pasar argumentos pero no como cadenas, por ejemplo lista? ¿Hay otra opción que pasar cada elemento por separado? – Michu93

+0

No use shell = True a menos que sea necesario. –

25

Creo que la buena práctica puede ser algo como esto;

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) 

según la documentación El módulo subproceso le permite obtener nuevos procesos, conectarse a sus tuberías de entrada/salida/error, y obtener sus códigos de retorno. Este módulo tiene la intención de reemplazar varios módulos antiguos y funciones:

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

Uso comunicarse() en lugar de .stdin.write, .stdout.read o .stderr.read para evitar los puntos muertos debido a cualquiera de los otros tampones de tubería OS llenando y bloqueando el proceso del niño. Read Here

Cuestiones relacionadas