467,211 Members | 1,213 Online
Bytes | Developer Community
Ask Question

Home New Posts Topics Members FAQ

Post your question to a community of 467,211 developers. It's quick & easy.

why a main() function?

I think I read a suggestion somewhere to wrap the code where a Python
script starts in a main() function, so one has

def main():
print "hi"

main()

instead of

print "hi"

What are the advantages of doing this?

Sep 18 '06 #1
  • viewed: 28009
Share:
19 Replies

be*******@aol.com wrote:
I think I read a suggestion somewhere to wrap the code where a Python
script starts in a main() function, so one has

def main():
print "hi"

main()

instead of

print "hi"

What are the advantages of doing this?

I'm sure there are other reasons, but for me the most important is that
you can import your code into the interpreter and poke at it from there
without executing the script. Also, of course, you can re-use your
code as a module in another program.

-Ben

Sep 18 '06 #2
On 18 Sep 2006 12:40:00 -0700, be*******@aol.com <be*******@aol.comwrote:
I think I read a suggestion somewhere to wrap the code where a Python
script starts in a main() function, so one has

def main():
print "hi"

main()

instead of

print "hi"

What are the advantages of doing this?
It is useful both importating scripts without running them, for
debugging or reusing parts of them later, and also for adding small
test scripts to modules to allow them to be run for testing purposes.
Sep 18 '06 #3
be*******@aol.com wrote:
I think I read a suggestion somewhere to wrap the code where a Python
script starts in a main() function, so one has

def main():
print "hi"

main()

instead of

print "hi"

What are the advantages of doing this?
Refine this to:

def main():
print "hi"

if __name__ == "__main__":
main()

The advantage of the 'if __name__ ..' statement is that you can import the
script without running the 'main' code, e.g. from your unittest module.

Wrapping the main code in a function allows you to call this function from
your unittests and test it like any other function.

Additionally I do usually add an 'argv' argument to main() which I use
instead of sys.argv, so I can easily test it with different arguments.

--
Benjamin Niemann
Email: pink at odahoda dot de
WWW: http://pink.odahoda.de/
Sep 18 '06 #4
be*******@aol.com wrote:
I think I read a suggestion somewhere to wrap the code where a Python
script starts in a main() function, so one has

def main():
print "hi"

main()

instead of

print "hi"

What are the advantages of doing this?
Guido van Rossum himself can tell you:

http://www.artima.com/forums/flat.js...06&thread=4829

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://holdenweb.blogspot.com
Recent Ramblings http://del.icio.us/steve.holden

Sep 18 '06 #5
Others have already told you the most important things.

There is another secondary advantage: the code inside a function runs
faster (something related is true for C programs too). Usually this
isn't important, but for certain programs they can go 20%+ faster.

Bye,
bearophile

Sep 18 '06 #6
Steve Holden <st***@holdenweb.comwrites:
be*******@aol.com wrote:
I think I read a suggestion somewhere to wrap the code where a
Python script starts in a main() function
[...]
What are the advantages of doing this?
Guido van Rossum himself can tell you:
http://www.artima.com/forums/flat.js...06&thread=4829
I read that one a while ago, and now have this in most of my programs:

def __main__(argv=None):
""" Perform the main function of this program """
from sys import argv as sys_argv
if argv is None:
argv = sys_argv

# preparation, e.g. set up environment

exit_code = None
try:
do_the_main_thing(argv) # or whatever the main step is
except SystemError, e:
exit_code = e.code

return exit_code

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

This allows me to import my program as a module, and treat the main
routine as a function (argv as input, exit_code as output), while the
code itself can do sys.exit() without needing to know that it's
wrapped up in a function.

It also encourages me to write code inside do_the_main_thing() that
gets its environment parameterised as input, instead of specifying
sys.argv and the like. This makes the code much easier to unit test.

The name __main__ was chosen because I saw hints some time ago that
Python 3000 might automate some of these semantics for a function with
that name. True or false?

--
\ "Crime is contagious ... if the government becomes a |
`\ lawbreaker, it breeds contempt for the law." -- Justice Louis |
_o__) Brandeis |
Ben Finney

Sep 19 '06 #7
On 18 Sep 2006 14:38:12 -0700,
be************@lycos.com wrote:
... There is another secondary advantage: the code inside a function
runs faster (something related is true for C programs too). Usually
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
this isn't important, but for certain programs they can go 20%+
faster.
Okay, I give up.

AFAIK, All C code must be inside a function, unless you count the
expressions in initializers.

So aside from certain CPU/MMU/OS/cache/etc. quirks, why would C code
inside a function run faster than C code outside a function? Compiler
optimizations because of const and restrict keywords don't count.

And what other C code *isn't* inside a function?

Regards,
Dan

--
Dan Sommers
<http://www.tombstonezero.net/dan/>
"I wish people would die in alphabetical order." -- My wife, the genealogist
Sep 19 '06 #8
Another advantage is that you can catch all the unhandled exceptions of
the entire program (it they occurs) by doing something like this:

def another_call():
raise SomeUnexpectedException # it will be catched in '__main__'

def call():
another_call()

def run():
call()

in __name__ == '__main__':
try:
run()
except:
# do cleanup
# log exit message
# exit

Sep 19 '06 #9
be************@lycos.com wrote:
Others have already told you the most important things.

There is another secondary advantage: the code inside a function runs
faster (something related is true for C programs too). Usually this
isn't important, but for certain programs they can go 20%+ faster.
I totally fail to see why that should be the case - for python as well as
for C.

So - can you explain that a bit more, or provide resources to read up on it?

Diez
Sep 19 '06 #10
On 9/19/06, Diez B. Roggisch <de***@nospam.web.dewrote:
I totally fail to see why that should be the case - for python as well as
for C.
If you put your code into a main() function, all the names that it
binds are in the function's local scope, whereas if the code is in the
module's top level, the names are bound to the module's global scope.
Access to locals is somewhat faster than access to globals.

--
Cheers,
Simon B,
si***@brunningonline.net,
http://www.brunningonline.net/simon/blog/
Sep 19 '06 #11
"Diez B. Roggisch" wrote:
>There is another secondary advantage: the code inside a function runs
faster (something related is true for C programs too). Usually this
isn't important, but for certain programs they can go 20%+ faster.

I totally fail to see why that should be the case - for python as well as
for C.

So - can you explain that a bit more, or provide resources to read up on it?
Python stores local variables in an indexed array, but globals in a dictionary.
Looking things up by index is faster than looking them up by name.

Not sure what the C thing is; C doesn't really support putting *code* outside
functions. Maybe he was thinking about static vs. auto variables ?

</F>

Sep 19 '06 #12
Diez B. Roggisch wrote:
be************@lycos.com wrote:
>Others have already told you the most important things.

There is another secondary advantage: the code inside a function runs
faster (something related is true for C programs too). Usually this
isn't important, but for certain programs they can go 20%+ faster.

I totally fail to see why that should be the case - for python as well as
for C.

So - can you explain that a bit more, or provide resources to read up on
it?
A trivial example (for Python):

$ cat main.py
def main():
x = 42
for i in xrange(1000000):
x; x; x; x; x; x; x; x; x; x
x; x; x; x; x; x; x; x; x; x
x; x; x; x; x; x; x; x; x; x

main()
$ time python main.py

real 0m0.874s
user 0m0.864s
sys 0m0.009s
$ cat nomain.py
x = 42
for i in xrange(1000000):
x; x; x; x; x; x; x; x; x; x
x; x; x; x; x; x; x; x; x; x
x; x; x; x; x; x; x; x; x; x
$ time python nomain.py

real 0m2.154s
user 0m2.145s
sys 0m0.009s
$

Now let's verify that global variables are responsible for the extra time:

$ cat main_global.py
def main():
global i, x
x = 42
for i in xrange(1000000):
x; x; x; x; x; x; x; x; x; x
x; x; x; x; x; x; x; x; x; x
x; x; x; x; x; x; x; x; x; x

main()
$ time python main_global.py

real 0m2.002s
user 0m1.995s
sys 0m0.007s
Peter

Sep 19 '06 #13
Fredrik Lundh wrote:
"Diez B. Roggisch" wrote:
>>There is another secondary advantage: the code inside a function runs
faster (something related is true for C programs too). Usually this
isn't important, but for certain programs they can go 20%+ faster.

I totally fail to see why that should be the case - for python as well as
for C.

So - can you explain that a bit more, or provide resources to read up on
it?

Python stores local variables in an indexed array, but globals in a
dictionary. Looking things up by index is faster than looking them up by
name.
Interesting. How is the index computed? I would have assumed that locals()
is somehow used, which is a dicht.

I can imagine enumerating left-hand-side names and trying to replace their
occurence with the index, falling back to the name if that is not
possible/the index isn't found. Does that come close?

Diez
Sep 19 '06 #14
"Diez B. Roggisch" <de***@nospam.web.dewrites:
Python stores local variables in an indexed array, but globals in a
dictionary. Looking things up by index is faster than looking them up by
name.

Interesting. How is the index computed? I would have assumed that locals()
is somehow used, which is a dicht.
They're static indexes assigned at compile time.
Sep 19 '06 #15
In <7x************@ruckus.brouhaha.com>, Paul Rubin wrote:
"Diez B. Roggisch" <de***@nospam.web.dewrites:
Python stores local variables in an indexed array, but globals in a
dictionary. Looking things up by index is faster than looking them up by
name.

Interesting. How is the index computed? I would have assumed that locals()
is somehow used, which is a dicht.

They're static indexes assigned at compile time.
Which BTW is the reason why ``locals()['answer'] = 42`` does not work
within functions. The dictionary isn't the dictionary that's used for
locals but a proxy just for read access.

Ciao,
Marc 'BlackJack' Rintsch

Sep 19 '06 #16
Diez B. Roggisch wrote:
Interesting. How is the index computed? I would have assumed that locals()
is somehow used, which is a dicht.

I can imagine enumerating left-hand-side names and trying to replace their
occurence with the index, falling back to the name if that is not
possible/the index isn't found. Does that come close?
yes, but there is no fallback: if a name inside a function is local or
not is decided once and for all by the compiler, using static analysis.
see:

http://pyref.infogami.com/naming-and-binding

</F>

Sep 19 '06 #17
Steve Holden wrote:
be*******@aol.com wrote:
>I think I read a suggestion somewhere to wrap the code where a Python
script starts in a main() function, so one has

def main():
print "hi"

main()

instead of

print "hi"

What are the advantages of doing this?
Guido van Rossum himself can tell you:

http://www.artima.com/forums/flat.js...06&thread=4829
Interesting. A lot of the suggestions he makes are unnecessary if you
use argparse_ or optparse, since they do much cleaner argument parsing
and error reporting.

I basically never write a main() function in the sense described here.
My code usually looks something like:

if __name__ == '__main__':
parser = _argparse.ArgumentParser(...)
parser.add_argument(...)
...
arguments = parser.parse_args()

function_that_actually_does_stuff(arguments.foo,
arguments.bar,
arguments.baz)

So my ``if __name__ == '__main__'`` block does just enough argument
parsing to be able to call a real function.

... _argparse: http://argparse.python-hosting.com/

STeVe
Sep 19 '06 #18
be*******@aol.com wrote:
I think I read a suggestion somewhere to wrap the code where a Python
script starts in a main() function, so one has
<snip>
What are the advantages of doing this?
Others have stated all the good ones, so I'll state a slightly dumber
one for us part time amateur hackers :)

If you start off writing all your python module inside a main function
then as you chop your code up into other functions (refactoring), the
code inside main is already at the proper indentation level for the new
top level functions. No more indenting it one level further to suit
the functions indentation.

--
Cheers
Anton

Sep 20 '06 #19
an********@gmail.com wrote:
be*******@aol.com wrote:
>I think I read a suggestion somewhere to wrap the code where a Python
script starts in a main() function, so one has

<snip>
>What are the advantages of doing this?

Others have stated all the good ones, so I'll state a slightly dumber
one for us part time amateur hackers :)

If you start off writing all your python module inside a main function
then as you chop your code up into other functions (refactoring), the
code inside main is already at the proper indentation level for the new
top level functions. No more indenting it one level further to suit
the functions indentation.
That is also true if you start by putting all the main code inside an 'if
__name__=="__main__":' block. Besides, how hard is it to select the code
and hit tab or whatever the 'indent region' command is in your editor?

FWIW, my scripts generally evolve through several stages.

So looking at one I wrote recently I see that it started with a few lines
at the outer level which quickly went inside a __name__=='__main__' block
(so I could prod functions in the script interactively). Then as it grew
larger the script moved into a main() function and some argument processing
appeared in the __main__ block (and all the support functions disappeared
into a separate module). Then I wanted some exception handling at the outer
level so now I have the __main__ block containing outer level exception
handling, and calling main() which does argument processing and calls
script() which contains the original script.

It may evolve further: main() is a bit too large at the moment, and I think
I want to move the original script into another module with a command line
argument to select between scripts. My point being that I don't have a hard
and fast rule: I do whatever seems to make the code read clearly at the
time.
Sep 20 '06 #20

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by wongjoekmeu@yahoo.com | last post: by
89 posts views Thread by Sweety | last post: by
1 post views Thread by wayne.denier@gmail.com | last post: by
5 posts views Thread by PencoOdStip@gmail.com | last post: by
11 posts views Thread by aarklon@gmail.com | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.