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 thoughts on “if __name__ == ‘__main__’ can be nicer!”

  1. 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.

  2. 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 :)

    1. I was more interested in the aesthetics when thinking of this module :)

      I do agree with the knowledge problem. It is reasonably obvious, but yes, one would check out the module to see what it was doing.

      If it was inbuilt into Python it would be quite a nice feature that all programmers would learn.

      1. So, did you push it as a PEP? Seems fairly non-controversial to me. Those who don’t want to use it won’t be affected…and it certainly looks more pythonic.

        1. Matt Curtis on StackOverflow (http://stackoverflow.com/questions/4777031/shortcut-for-if-name-main/4813472#4813472) pointed to a similar PEP:
          http://www.python.org/dev/peps/pep-0299/

          With it being rejected:

          Rejection
          In a short discussion on python-dev [1], two major backwards
          compatibility problems were brought up and Guido pronounced that he
          doesn’t like the idea anyway as it’s “not worth the change (in docs,
          user habits, etc.) and there’s nothing particularly broken.”

  3. # 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()

    1. 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()

  4. Also, something closer to being useful:

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

  5. 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.

Comments are closed.