En Python, ¿puedo llamar al main () de un módulo importado?

En Python tengo un módulo myModule.py donde defino algunas funciones y main () , lo que requiere algunos argumentos de la línea de comandos.

Normalmente llamo a este main () desde un script de bash. Ahora, me gustaría poner todo en un paquete pequeño, así que pensé que tal vez podría convertir mi simple script de bash en un script de Python y ponerlo en el paquete.

Entonces, ¿cómo llamo a la función main () de myModule.py desde la función main () de MyFormerBashScript.py? ¿Puedo incluso hacer eso? ¿Cómo le paso cualquier argumento ?

Es sólo una función. Importarlo y llamarlo:

 import myModule myModule.main() 

Si necesita analizar argumentos, tiene dos opciones:

  • Analícelos en main() , pero pase sys.argv como parámetro (todo el código a continuación en el mismo módulo myModule ):

     def main(args): # parse arguments using optparse or argparse or what have you if __name__ == '__main__': import sys main(sys.argv[1:]) 

    Ahora puede importar y llamar a myModule.main(['arg1', 'arg2', 'arg3']) desde otro módulo.

  • Haga que main() acepte los parámetros que ya están analizados (de nuevo todo el código en el módulo myModule ):

     def main(foo, bar, baz='spam'): # run with already parsed arguments if __name__ == '__main__': import sys # parse sys.argv[1:] using optparse or argparse or what have you main(foovalue, barvalue, **dictofoptions) 

    e importe y llame a myModule.main(foovalue, barvalue, baz='ham') cualquier otro lugar y envíe los argumentos de python según sea necesario.

El truco aquí es detectar cuándo su módulo se está utilizando como un script; cuando ejecuta un archivo de Python como el script principal ( python filename.py ) no se está utilizando una statement de import , por lo que Python llama a ese módulo "__main__" . Pero si ese mismo código de filename.py se trata como un módulo ( import filename ), entonces Python usa eso como el nombre del módulo. En ambos casos, la variable __name__ está configurada, y las pruebas __name__ le __name__ cómo se ejecutó su código.

La respuesta de Martijen tiene sentido, pero faltaba algo crucial que puede parecer obvio para otros, pero fue difícil para mí entenderlo.

En la versión donde usa argparse, necesita tener esta línea en el cuerpo principal.

 args = parser.parse_args(args) 

Normalmente, cuando estás usando argparse solo en un script, solo escribes

 args = parser.parse_args() 

y parse_args encuentra los argumentos desde la línea de comando. Pero en este caso, la función principal no tiene acceso a los argumentos de la línea de comandos, por lo que tiene que decirle a argparse cuáles son los argumentos.

Aquí hay un ejemplo

 import argparse import sys def x(x_center, y_center): print "X center:", x_center print "Y center:", y_center def main(args): parser = argparse.ArgumentParser(description="Do something.") parser.add_argument("-x", "--xcenter", type=float, default= 2, required=False) parser.add_argument("-y", "--ycenter", type=float, default= 4, required=False) args = parser.parse_args(args) x(args.xcenter, args.ycenter) if __name__ == '__main__': main(sys.argv[1:]) 

Suponiendo que haya nombrado a este mytest.py Para ejecutarlo, puede hacer cualquiera de estos desde la línea de comandos

 python ./mytest.py -x 8 python ./mytest.py -x 8 -y 2 python ./mytest.py 

que devuelve respectivamente

 X center: 8.0 Y center: 4 

o

 X center: 8.0 Y center: 2.0 

o

 X center: 2 Y center: 4 

O si quieres ejecutar desde otro script de Python puedes hacerlo

 import mytest mytest.main(["-x","7","-y","6"]) 

que devuelve

 X center: 7.0 Y center: 6.0 

Depende. Si el código principal está protegido por un if como en:

 if __name__ == '__main__': ...main code... 

entonces no, no puedes hacer que Python lo ejecute porque no puedes influir en la variable automática __name__ .

Pero cuando todo el código está en una función, entonces podría ser capaz de hacerlo. Tratar

 import myModule myModule.main() 

Esto funciona incluso cuando el módulo se protege con un __all__ .

from myModule import * puede que main no esté visible para usted, por lo que realmente necesita importar el módulo.

Tuve la misma necesidad de usar argparse también. La cosa es que la función parse_args de una instancia de objeto argparse.ArgumentParser toma implícitamente sus argumentos de forma predeterminada de sys.args . La parse_args , siguiendo la línea de Martijn, consiste en hacer eso explícito, para que pueda cambiar los argumentos que pase a parse_args como desee.

 def main(args): # some stuff parser = argparse.ArgumentParser() # some other stuff parsed_args = parser.parse_args(args) # more stuff with the args if __name__ == '__main__': import sys main(sys.argv[1:]) 

El punto clave es pasar args a la función parse_args . Más tarde, para usar el main, solo haces lo que Martijn dice.

Suponiendo que usted está tratando de pasar los argumentos de la línea de comandos también.

 import sys import myModule def main(): # this will just pass all of the system arguments as is myModule.main(*sys.argv) # all the argv but the script name myModule.main(*sys.argv[1:]) 

La respuesta que estaba buscando fue respondida aquí: ¿Cómo usar python argparse con args que no sean sys.argv?

Si main.py y parse_args() se escriben de esta manera, entonces el análisis se puede hacer muy bien

 # main.py import argparse def parse_args(): parser = argparse.ArgumentParser(description="") parser.add_argument('--input', default='my_input.txt') return parser def main(args): print(args.input) if __name__ == "__main__": parser = parse_args() args = parser.parse_args() main(args) 

Luego, puede llamar a main() y analizar argumentos con parser.parse_args(['--input', 'foobar.txt']) en otro script de python:

 # temp.py from main import main, parse_args parser = parse_args() args = parser.parse_args([]) # note the square bracket # to overwrite default, use parser.parse_args(['--input', 'foobar.txt']) print(args) # Namespace(input='my_input.txt') main(args)