Dark Fighter free for a limited time
 

Dark Fighter

Now FREE on the App Store!

 
Gravit universal binary released for Mac OS X
 

Gravit released for OS X

A free Gravity Simulator

 
TowerDefend is now $0.99!
 

Tower Defend - ON SALE

Price reduced to 0.99 USD!

 

if __name__ == ‘__main__’ can be nicer!

After many times of writing out this default “main” code, I decided to work out if there is a way that I don’t have to type as much and make it look nicer. Yes, I’m pedantic with code neatness. Here is an example of what I’m talking about:

def main():
    print 'this runs only when executed directly'

if __name__ == '__main__':
    main()

I asked on Stack Overflow, but the general answer was “deal with it”. After a quick discussion of the problem, @dsturnbull and myself worked out that it was possible to import a module and use a decorator in place of this if statement.

The module is called automain, and here is an example of its usage:

from automain import *

@automain
def main():
    print 'this runs only when executed directly'

I threw it on github, and Python Cheese Shop and it can be easy_installed:

easy_install automain

How does it work?
The source code of the decorator looks like this:

def automain(func):
    import inspect
    parent = inspect.stack()[1][0]
    name = parent.f_locals.get('__name__', None)
    if name == '__main__':
        func()

Basically it inspects the parent stack frame, and checks if __name__ is ‘__main__’, then executes the function. Otherwise it does nothing, as expected.

Internet Trolls
Interestingly enough, a random internet troll rated the module 0/5 on Python Cheese Shop and started his comment with:

spookylukey (2011-01-24, 0 points):
Seriously? Is this a joke?

1. Your implementation can’t possible work – it is going to do the same if the module is imported as a library or if it is run as a script.
[..snip..]

All I have to say is that it does work and I find it much better to use. Thanks for the terrible and incorrect feedback though, spookylukey!

12 Comments

  1. [...] This post was mentioned on Twitter by Gerald Kaszuba, Slowchop Studios. Slowchop Studios said: if __name__ == ‘__main__’ can be nicer! http://goo.gl/fb/lbrk6 #coding #python [...]

  2. Will McGugan says:

    If you import your module, is the ‘main’ function available? From scanning the code it looks like it returns None if it is not __main__, rendering that function invisible to code that imports it.

    Perhaps the decorator should return func at the end.

  3. Marcus Breese says:

    I don’t doubt that this works, but this is roughly the same amount of typing when you include the ‘import’ and decorator… so I don’t know what you’re gaining, except aesthetics. That and every other Python programmer not having a clue what @automain is :)

  4. Mark Richards says:

    # automain doesn’t work on recursive functions since the function isn’t defined yet…
    from automain import *
    depth = 10
    @automain
    def main():
    global depth
    if depth > 0:
    print ‘depth is’, depth
    depth -= 1
    main()

    • Mark Richards says:

      The spaces in the code got lost, so how about (carets are spaces):

      from automain import *
      depth = 10
      @automain
      def main():
      ^^^^global depth
      ^^^^if depth > 0:
      ^^^^^^^^print ‘depth is’, depth
      ^^^^^^^^depth -= 1
      ^^^^^^^^main()

  5. Mark Richards says:

    Also, something closer to being useful:

    from automain import *
    @automain
    def draw(n=30):
    ^^^^if n > 0:
    ^^^^^^^^print ‘*’ * n
    ^^^^^^^^draw(n – 1)

  6. Mark Richards says:

    This one lacks recursion, but should be common:

    from automain import *
    @automain
    def main():
    ^^^^print helper()
    def helper():
    ^^^^return 5

    Using the old (ugly) notation, this is possible (just put if __name__ == ‘__main__’: at the end), though not recommended.

    P.S. Despite my comments, I still use @automain in my code.