web-dev-qa-db-fra.com

En Python, puis-je appeler le main () d'un module importé?

En Python, j'ai un module myModule.py où je définis quelques fonctions et un main (), qui prend quelques arguments en ligne de commande. 

J'appelle généralement this main () à partir d'un script bash. Maintenant, je voudrais tout mettre dans un petit paquet, alors j'ai pensé que je pourrais peut-être transformer mon script bash simple en un script Python et le mettre dans le paquet.

Alors, comment puis-je réellement appeler la fonction main () de myModule.py de la fonction main () de MyFormerBashScript.py? Puis-je même faire ça? Comment est-ce que je peux lui passer des arguments?

49
Ricky Robinson

C'est juste une fonction. Importez-le et appelez-le:

import myModule

myModule.main()

Si vous devez analyser des arguments, vous avez deux options:

  • Les analyser dans main(), mais passez sys.argv en tant que paramètre (tout le code ci-dessous dans le même module myModule):

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

    Vous pouvez maintenant importer et appeler myModule.main(['arg1', 'arg2', 'arg3']) depuis un autre module.

  • Avez-main() accepter les paramètres déjà analysés (encore une fois tout le code dans le module myModule):

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

    et importez et appelez myModule.main(foovalue, barvalue, baz='ham') ailleurs et passez des arguments python si nécessaire.

Le truc ici est de détecter quand votre module est utilisé comme script; Lorsque vous exécutez un fichier python en tant que script principal (python filename.py), aucune instruction import n'est utilisée. Python appelle donc ce module "__main__". Mais si ce même code filename.py est traité comme un module (import filename), python l’utilisera alors comme nom de module. Dans les deux cas, la variable __name__ est définie et les tests correspondants indiquent comment votre code a été exécuté.

72
Martijn Pieters

La réponse de Martijen est logique, mais il lui manquait quelque chose de crucial qui peut sembler évident aux autres, mais que j'ai eu du mal à comprendre.

Dans la version où vous utilisez argparse, vous devez avoir cette ligne dans le corps principal.

args = parser.parse_args(args)

Normalement, lorsque vous utilisez argparse dans un script, vous écrivez

args = parser.parse_args()

et parse_args trouvent les arguments à partir de la ligne de commande. Mais dans ce cas, la fonction principale n'a pas accès aux arguments de la ligne de commande. Vous devez donc indiquer à argparse quels sont les arguments.

Voici un exemple 

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 __== '__main__':
    main(sys.argv[1:])

En supposant que vous ayez nommé mytest.py Pour l'exécuter, vous pouvez exécuter l'une de ces opérations depuis la ligne de commande.

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

qui retourne respectivement

X center: 8.0
Y center: 4

ou

X center: 8.0
Y center: 2.0

ou

X center: 2
Y center: 4

Ou si vous voulez exécuter un autre script python, vous pouvez le faire

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

qui retourne 

X center: 7.0
Y center: 6.0
23
barry solomon

Ça dépend. Si le code principal est protégé par une if comme dans:

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

alors non, vous ne pouvez pas faire exécuter cela par Python car vous ne pouvez pas influencer la variable automatique __name__.

Mais quand tout le code est dans une fonction, alors peut-être en mesure de le faire. Essayer

import myModule

myModule.main()

Cela fonctionne même lorsque le module se protège avec un __all__

from myModule import * peut ne pas rendre main visible pour vous, vous devez donc importer le module lui-même.

19
Aaron Digulla

J'ai eu le même besoin en utilisant argparse aussi. La chose est la fonction parse_args d'une instance d'objet argparse.ArgumentParser prend implicitement ses arguments par défaut à partir de sys.args. La solution autour de Martijn consiste à rendre cela explicite afin que vous puissiez modifier les arguments que vous transmettez en parse_args selon vos souhaits.

def main(args):
    # some stuff
    parser = argparse.ArgumentParser()
    # some other stuff
    parsed_args = parser.parse_args(args)
    # more stuff with the args

if __== '__main__':
    import sys
    main(sys.argv[1:])

Le point clé est de passer les arguments à la fonction parse_args de la fonction . Plus tard, pour utiliser le paramètre principal, faites comme Martijn.

2
eguaio

Voici la réponse que je cherchais: Comment utiliser python argparse avec des arguments autres que sys.argv?

Si main.py et parse_args() sont écrits de cette façon, l’analyse peut être faite correctement

# 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 __== "__main__":
    parser = parse_args()
    args = parser.parse_args()
    main(args)

Ensuite, vous pouvez appeler main() et analyser les arguments avec parser.parse_args(['--input', 'foobar.txt']) dans un autre script 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)
0
Sida Zhou

En supposant que vous tentiez également de transmettre les arguments de ligne de commande.

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:])
0
agoebel