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?
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é.
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
Ç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.
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.
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)
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:])