In Python, can I call the main() of an imported module?

后端 未结 6 2002
时光取名叫无心
时光取名叫无心 2020-11-29 17:36

In Python I have a module myModule.py where I define a few functions and a main(), which takes a few command line arguments.

I usu

相关标签:
6条回答
  • 2020-11-29 17:45

    Assuming you are trying to pass the command line arguments as well.

    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 讨论(0)
  • 2020-11-29 17:50

    It's just a function. Import it and call it:

    import myModule
    
    myModule.main()
    

    If you need to parse arguments, you have two options:

    • Parse them in main(), but pass in sys.argv as a parameter (all code below in the same module myModule):

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

      Now you can import and call myModule.main(['arg1', 'arg2', 'arg3']) from other another module.

    • Have main() accept parameters that are already parsed (again all code in the myModule module):

      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)
      

      and import and call myModule.main(foovalue, barvalue, baz='ham') elsewhere and passing in python arguments as needed.

    The trick here is to detect when your module is being used as a script; when you run a python file as the main script (python filename.py) no import statement is being used, so python calls that module "__main__". But if that same filename.py code is treated as a module (import filename), then python uses that as the module name instead. In both cases the variable __name__ is set, and testing against that tells you how your code was run.

    0 讨论(0)
  • 2020-11-29 17:57

    It depends. If the main code is protected by an if as in:

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

    then no, you can't make Python execute that because you can't influence the automatic variable __name__.

    But when all the code is in a function, then might be able to. Try

    import myModule
    
    myModule.main()
    

    This works even when the module protects itself with a __all__.

    from myModule import * might not make main visible to you, so you really need to import the module itself.

    0 讨论(0)
  • 2020-11-29 18:00

    The answer I was searching for was answered here: How to use python argparse with args other than sys.argv?

    If main.py and parse_args() is written in this way, then the parsing can be done nicely

    # 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)
    

    Then you can call main() and parse arguments with parser.parse_args(['--input', 'foobar.txt']) to it in another python script:

    # 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 讨论(0)
  • 2020-11-29 18:01

    I had the same need using argparse too. The thing is parse_args function of an argparse.ArgumentParser object instance implicitly takes its arguments by default from sys.args. The work around, following Martijn line, consists of making that explicit, so you can change the arguments you pass to parse_args as desire.

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

    The key point is passing args to parse_args function. Later, to use the main, you just do as Martijn tell.

    0 讨论(0)
  • 2020-11-29 18:05

    Martijen's answer makes sense, but it was missing something crucial that may seem obvious to others but was hard for me to figure out.

    In the version where you use argparse, you need to have this line in the main body.

    args = parser.parse_args(args)
    

    Normally when you are using argparse just in a script you just write

    args = parser.parse_args()
    

    and parse_args find the arguments from the command line. But in this case the main function does not have access to the command line arguments, so you have to tell argparse what the arguments are.

    Here is an example

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

    Assuming you named this mytest.py To run it you can either do any of these from the command line

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

    which returns respectively

    X center: 8.0
    Y center: 4
    

    or

    X center: 8.0
    Y center: 2.0
    

    or

    X center: 2
    Y center: 4
    

    Or if you want to run from another python script you can do

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

    which returns

    X center: 7.0
    Y center: 6.0
    
    0 讨论(0)
提交回复
热议问题