Is there any advantage to using a main() in python scripts?

J

JL

Python scripts can run without a main(). What is the advantage to using a main()? Is it necessary to use a main() when the script uses command line arguments? (See script below)

#!/usr/bin/python

import sys

def main():
# print command line arguments
for arg in sys.argv[1:]:
print arg

if __name__ == "__main__":
main()
 
C

Chris Angelico

except SystemExit, exc:

For new code, you'd of course want to write that as:

except SystemExit as exc:

which is compatible with Python 2.6, 2.7, and 3.x, while the other
syntax is 2.x only.

ChrisA
 
M

marduk

I would agree with the previous post but also add that I've stopped
calling the main function "main()" and usually give it a more
descriptive name, such as "bake_cookies()" or whatever. I think that
that makes it clearer what it's doing when used as a library and the 'if
__name__ == '__main__'" already implies that it is the "main" script
function.
 
R

Roy Smith

JL said:
Python scripts can run without a main(). What is the advantage to using a
main()? Is it necessary to use a main() when the script uses command line
arguments? (See script below)

#!/usr/bin/python

import sys

def main():
# print command line arguments
for arg in sys.argv[1:]:
print arg

if __name__ == "__main__":
main()

No, it's not necessary, but it's a good idea.

For one thing, it lets you import your script without actually running
it. We recently tracked down a long-standing bug where some maintenance
script we had started out with:

import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'whatever'

somebody imported that script in another part of the system because
there was some convenient definition that he wanted to reuse.
Unfortunately, the act of importing the script changed the environment!

The fix was to move the setting of the environment variable to inside
the main() routine. If you always follow the rule that you always put
all your executable code inside main(), you'll never run into problems
like that.
 
R

Roy Smith

I would agree with the previous post but also add that I've stopped
calling the main function "main()" and usually give it a more
descriptive name, such as "bake_cookies()" or whatever. I think that
that makes it clearer what it's doing when used as a library and the 'if
__name__ == '__main__'" already implies that it is the "main" script
function.

If you're writing a library that's meant to be imported by other
scripts, then that makes sense. I tend to use main() for things that
are done when your script is run as a stand-alone program. That usually
involves things like parsing command-line arguments, and configuring
logging, neither of which you'd want to do in an importable library.
 
R

rusi

JL wrote:
Python scripts can run without a main(). What is the advantage to using a
main()? Is it necessary to use a main() when the script uses command line
arguments? (See script below)
#!/usr/bin/python
import sys
def main():
# print command line arguments
for arg in sys.argv[1:]:
print arg
if __name__ == "__main__":
main()
No, it's not necessary, but it's a good idea.
For one thing, it lets you import your script without actually running
it. We recently tracked down a long-standing bug where some maintenance
script we had started out with:
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'whatever'
somebody imported that script in another part of the system because
there was some convenient definition that he wanted to reuse.
Unfortunately, the act of importing the script changed the environment!
The fix was to move the setting of the environment variable to inside
the main() routine. If you always follow the rule that you always put
all your executable code inside main(), you'll never run into problems
like that.

I guess these are important but somewhat advanced considerations.

For a beginner, its important to get that there is a bit of a pun here:
The function habitually called 'main' may be called that or anything else
It can have or not have an argument as Ben pointed out -- maybe more than
one also.

The module name __main__ is however sacrosanct and hardwired into python.
The habit of connecting the one with the other is partly conventional and
partly unavoidable
 
B

bob gailer

What is the advantage to using a main()?
In addition to what's been said I add:

It separates all the global activities: defining of functions and
classes, importing modules, etc. from the "doing" the actual task of the
program.

It also ensures that the defining all the classes and functions happens
before referencing them (less "bookkeeping" for me).

These two allow me to write the main program first, and follow it with
all the global stuff.
 
C

Chris Angelico

It also ensures that the defining all the classes and functions happens
before referencing them (less "bookkeeping" for me).

These two allow me to write the main program first, and follow it with all
the global stuff.

I prefer define-before-use for readability, even if it doesn't matter
to the language. It means that locating the source of something can be
found by going upward (or starting at the top and going down - first
hit should be the definition), and helps keep things organized.
Obviously it's not always possible (mutual recursion, for instance),
but it's a general rule of thumb that I like to maintain.

ChrisA
 
T

Terry Reedy

Better design is to make the argument list a parameter to the ‘main’
function; this allows constructing an argument list specially for
calling that function, without ‘main’ needing to know the difference.

You'll also want to catch SystemExit and return that as the ‘main’
function's return value, to make it easier to use as a function when
that's needed.

def main(argv=None):
if argv is None:
argv = sys.argv

exit_code = 0
try:
command_name = argv[0]
config = parse_command_args(argv[1:])
do_whatever_this_program_does(config)
except SystemExit, exc:
exit_code = exc.code

return exit_code

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

That way, the normal behaviour is to use the ‘sys.argv’list and to
raise SystemExit (via ‘sys.exit’) to exit the program. But ‘main’ itself
can, without any further changes, be called as a function that receives
the command line as a parameter, and returns the exit code.

In particular, it is easier to write tests when argv is a parameter.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,019
Latest member
RoxannaSta

Latest Threads

Top