Putting the main program in a main function

Ben Finney ben+python at benfinney.id.au
Mon Sep 14 09:32:01 CEST 2015


"ast" <nomail at invalid.com> writes:

> The author says that with this structure there are no global variables
> (except when using "global' keyword) and that the program can be
> loaded as a module without be ran to test the function in the python
> shell.
>
> is it advised to always write programs like that ?

Writing all the code in functions makes your code more reliably tested:
you can write a unit test that exercises the code and know whether it is
behaving correctly.

Writing all the code in functions makes your code more understandable:
the possible interactions between different parts of the program are
more explicitly and strictly defined.

So yes, it's advisable to write a ‘main’ function for the application
and keep to absolute minimum the ‘if __name__ == "__main__"’ block.

That said, your ‘main’ function can be slightly more self-contained. The
paradigm for invoking a command-line program is that its input
parameters are the process's command-line arguments, and its return
value is the process's exit status.

So you can write a ‘main’ function that explicitly allows those input
and output to be handled as for a normal function::

    import sys

    def main(argv=None):
        """ Mainline code for this module.

            :param argv: The sequence of command-line arguments used to
                invoke this program. Defaults to `sys.argv`.
            :return: ``None``.

            """
        if argv is None:
            argv = sys.argv

        try:
            handle_the_command_line(argv)
            do_various_things()

        except SystemExit as exc:
            exit_status = exc.code
        else:
            # No exit requested; return “success” status.
            exit_status = 0

        return exit_status

    if __name__ == "__main__":
        exit_status = main(sys.argv)
        sys.exit(exit_status)

That way, the ‘if __name__ == "__main__"’ block will use the
conventional input (command-line arguments) and output (process exit
status); the rest of the application code may call ‘sys.exit’ or raise
‘SystemExit’ as normal; but your code will wrap it all up as the inputs
and outputs of the ‘main’ function, making it much easier to control for
testing.

Python's BDFL wrote an article many years ago describing this pattern
<URL:http://www.artima.com/weblogs/viewpost.jsp?thread=4829>, mine is a
small refinement of that.

-- 
 \         “It is the fundamental duty of the citizen to resist and to |
  `\          restrain the violence of the state.” —Noam Chomsky, 1971 |
_o__)                                                                  |
Ben Finney



More information about the Python-list mailing list