Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #80626 > unrolled thread

How about some syntactic sugar for " __name__ == '__main__' "?

Started byJohn Ladasky <john_ladasky@sbcglobal.net>
First post2014-11-12 13:02 -0800
Last post2014-12-02 02:17 -0800
Articles 11 on this page of 31 — 11 participants

Back to article view | Back to comp.lang.python


Contents

  How about some syntactic sugar for " __name__ == '__main__' "? John Ladasky <john_ladasky@sbcglobal.net> - 2014-11-12 13:02 -0800
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Joel Goldstick <joel.goldstick@gmail.com> - 2014-11-12 16:07 -0500
    Re: How about some syntactic sugar for " __name__ == '__main__' "? John Ladasky <john_ladasky@sbcglobal.net> - 2014-11-12 13:17 -0800
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ethan Furman <ethan@stoneleaf.us> - 2014-11-12 13:19 -0800
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Chris Kaynor <ckaynor@zindagigames.com> - 2014-11-12 13:33 -0800
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Marko Rauhamaa <marko@pacujo.net> - 2014-11-12 23:52 +0200
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-12 14:51 -0700
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Skip Montanaro <skip.montanaro@gmail.com> - 2014-11-12 15:55 -0600
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Chris Kaynor <ckaynor@zindagigames.com> - 2014-11-12 14:09 -0800
      Re: How about some syntactic sugar for " __name__ == '__main__' "? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-11-15 22:09 +1100
        Re: How about some syntactic sugar for " __name__ == '__main__' "? Marko Rauhamaa <marko@pacujo.net> - 2014-11-15 13:54 +0200
        Re: How about some syntactic sugar for " __name__ == '__main__' "? Vito De Tullio <vito.detullio@gmail.com> - 2014-11-16 11:26 +0100
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-12 15:19 -0700
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Terry Reedy <tjreedy@udel.edu> - 2014-11-12 18:19 -0500
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Chris Angelico <rosuav@gmail.com> - 2014-11-13 10:26 +1100
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Terry Reedy <tjreedy@udel.edu> - 2014-11-12 19:35 -0500
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Chris Angelico <rosuav@gmail.com> - 2014-11-13 11:54 +1100
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ethan Furman <ethan@stoneleaf.us> - 2014-11-13 10:32 -0800
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-13 13:33 -0700
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ethan Furman <ethan@stoneleaf.us> - 2014-11-13 12:43 -0800
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Skip Montanaro <skip.montanaro@gmail.com> - 2014-11-13 14:44 -0600
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Skip Montanaro <skip.montanaro@gmail.com> - 2014-11-13 14:53 -0600
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-13 15:48 -0700
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-13 15:56 -0700
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-11-15 21:52 +1100
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Vito De Tullio <vito.detullio@gmail.com> - 2014-11-16 11:39 +0100
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-16 10:15 -0700
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ethan Furman <ethan@stoneleaf.us> - 2014-12-01 15:19 -0800
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ethan Furman <ethan@stoneleaf.us> - 2014-12-01 16:45 -0800
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Chris Angelico <rosuav@gmail.com> - 2014-12-02 12:15 +1100
    Re: How about some syntactic sugar for " __name__ == '__main__' "? Ethan Furman <ethan@stoneleaf.us> - 2014-12-02 02:17 -0800

Page 2 of 2 — ← Prev page 1 [2]


#80702

FromSkip Montanaro <skip.montanaro@gmail.com>
Date2014-11-13 14:44 -0600
Message-ID<mailman.15788.1415911479.18130.python-list@python.org>
In reply to#80626
On Thu, Nov 13, 2014 at 2:33 PM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> ... other things decorated with atexit.register
> might actually be called before the main function

I don't think that will happen. The atexit module is documented to
execute its exit functions in reverse order. What's not documented is
the behavior of calling atexit.register() while atexit._run_exitfuncs
is running. That's an implementation detail, and though unlikely to
change, it might be worthwhile getting that behavior documented.

Skip

[toc] | [prev] | [next] | [standalone]


#80704

FromSkip Montanaro <skip.montanaro@gmail.com>
Date2014-11-13 14:53 -0600
Message-ID<mailman.15789.1415912047.18130.python-list@python.org>
In reply to#80626
On Thu, Nov 13, 2014 at 2:44 PM, Skip Montanaro
<skip.montanaro@gmail.com> wrote:
> What's not documented is
> the behavior of calling atexit.register() while atexit._run_exitfuncs
> is running. That's an implementation detail, and though unlikely to
> change, it might be worthwhile getting that behavior documented.

http://bugs.python.org/issue22867

Skip

[toc] | [prev] | [next] | [standalone]


#80709

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-11-13 15:48 -0700
Message-ID<mailman.15791.1415918976.18130.python-list@python.org>
In reply to#80626
On Thu, Nov 13, 2014 at 1:44 PM, Skip Montanaro
<skip.montanaro@gmail.com> wrote:
> On Thu, Nov 13, 2014 at 2:33 PM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>> ... other things decorated with atexit.register
>> might actually be called before the main function
>
> I don't think that will happen. The atexit module is documented to
> execute its exit functions in reverse order.

Right, so if something else gets registered after the main function,
it will be called before the main function.

> What's not documented is
> the behavior of calling atexit.register() while atexit._run_exitfuncs
> is running. That's an implementation detail, and though unlikely to
> change, it might be worthwhile getting that behavior documented.

Since the exit functions are executed in reverse order, anything
registered at this time would have to be called before something else
that has already been called, so I would expect this to be an error
condition.

[toc] | [prev] | [next] | [standalone]


#80710

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-11-13 15:56 -0700
Message-ID<mailman.15792.1415919443.18130.python-list@python.org>
In reply to#80626
On Thu, Nov 13, 2014 at 1:53 PM, Skip Montanaro
<skip.montanaro@gmail.com> wrote:
> On Thu, Nov 13, 2014 at 2:44 PM, Skip Montanaro
> <skip.montanaro@gmail.com> wrote:
>> What's not documented is
>> the behavior of calling atexit.register() while atexit._run_exitfuncs
>> is running. That's an implementation detail, and though unlikely to
>> change, it might be worthwhile getting that behavior documented.
>
> http://bugs.python.org/issue22867

In fact it seems the behavior does differ between Python 2.7 and Python 3.4:

$ cat testatexit.py
import atexit

@atexit.register
def main():
  atexit.register(goodbye)

@atexit.register
def goodbye():
  print("Goodbye")
$ python2 testatexit.py
Goodbye
Goodbye
$ python3 testatexit.py
Goodbye

[toc] | [prev] | [next] | [standalone]


#80816

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2014-11-15 21:52 +1100
Message-ID<54673077$0$12976$c3e8da3$5496439d@news.astraweb.com>
In reply to#80626
John Ladasky wrote:

> I have taught Python to several students over the past few years.  As I
> have worked with my students, I find myself bothered by the programming
> idiom that we use to determine whether a module is being executed or
> merely imported:
> 
>   "if __name__ == '__main__':"
> 
> The use of two dunder tokens -- one as a name in a namespace, and the
> other as a string, is intimidating.  It exposes too much of Python's guts.

The dunders are a tad ugly, but it's actually quite simple and elegant:

* every module has a global variable `__name__` which normally holds 
  the name of the module:


py> import functools
py> functools.__name__
'functools'
py> import math as foobarbaz
py> foobarbaz.__name__
'math'


* When Python imports a module, it sets the global __name__ to that 
  module's actual name (as taken from the file name).

* But when Python runs a file, as in `python2.7 path/to/script.py`, 
  it sets the global __name__ to the magic value '__main__' instead
  of "script".

The consequence is that every module can tell whether it is being run as a
script or not by inspecting the __name__ global. That's all there is to it.





-- 
Steven

[toc] | [prev] | [next] | [standalone]


#80874

FromVito De Tullio <vito.detullio@gmail.com>
Date2014-11-16 11:39 +0100
Message-ID<mailman.15883.1416134390.18130.python-list@python.org>
In reply to#80626
Ian Kelly wrote:

>> def main(func):
>>     if func.__module__ == "__main__":
>>             func()
>>     return func # The return could be omitted to block the function from
>> being manually called after import.
>>
>> Just decorate the "main" function of the script with that, and it will be
>> automatically called when ran as a script, but not when imported as a
>> module.
> 
> This calls it at the wrong time, though. Typically the way this idiom
> is used is that you define everything you need (functions, classes,
> etc.) within the main script, and then you call the main function.
> This would call the main function at the time it's defined, when other
> things in the main script may not have been defined yet. One could
> place the main function last, but it would be preferable not to be
> forced.

for the "right time" you can choose to spin a thread and wait to the end of 
the load of the module

something like



from threading import Thread, current_thread

def run_func(func, module_thread):
    module_thread.join()
    func()

def main(func):
    if func.__module__ == '__main__':
        Thread(target=run_func, args=[func, current_thread()]).start()

    return func


-- 
By ZeD

[toc] | [prev] | [next] | [standalone]


#80888

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-11-16 10:15 -0700
Message-ID<mailman.15889.1416158179.18130.python-list@python.org>
In reply to#80626
On Sun, Nov 16, 2014 at 3:39 AM, Vito De Tullio <vito.detullio@gmail.com> wrote:
> for the "right time" you can choose to spin a thread and wait to the end of
> the load of the module

Yuck. "Just add threads" is /not/ the answer to everything.

This case looks fairly harmless on the surface, although I could
imagine it breaking things that might object to the main thread being
changed, e.g. things that use event loops or that rely in some way on
the threading.main_thread() function.

[toc] | [prev] | [next] | [standalone]


#81787

FromEthan Furman <ethan@stoneleaf.us>
Date2014-12-01 15:19 -0800
Message-ID<mailman.16479.1417475999.18130.python-list@python.org>
In reply to#80626

[Multipart message — attachments visible in raw view] — view raw

On 11/13/2014 10:32 AM, Ethan Furman wrote:
> On 11/12/2014 01:51 PM, Ian Kelly wrote:
>> On Wed, Nov 12, 2014 at 2:33 PM, Chris Kaynor wrote:
>>>
>>> A decorator is an interesting idea, and should be easy to implement (only
>>> lightly tested):
>>>
>>> def main(func):
>>>      if func.__module__ == "__main__":
>>>              func()
>>>      return func # The return could be omitted to block the function from
>>> being manually called after import.
>>
>> This calls it at the wrong time, though.  [...]
> 
> One decorator that won't call too early is atexit.register().

Well, I've tried this out, and it's only okay.  As soon as interesting things start happening, spurious errors about
thread IDs start printing, which really messes up the user experience [1].


[1] something like Exception KeyError: KeyError(139924387112272,) in <module 'threading' from
'/usr/lib/python2.7/threading.pyc'> ignored

--
~Ethan~

[toc] | [prev] | [next] | [standalone]


#81788

FromEthan Furman <ethan@stoneleaf.us>
Date2014-12-01 16:45 -0800
Message-ID<mailman.16480.1417481122.18130.python-list@python.org>
In reply to#80626

[Multipart message — attachments visible in raw view] — view raw

On 12/01/2014 03:19 PM, Ethan Furman wrote:
> 
> Well, I've tried this out, and it's only okay.  As soon as interesting things start happening, spurious errors about 
> thread IDs start printing, which really messes up the user experience [...]

So here's another thought:  Have a small python script that loads and runs the actual script -- here's a POC:

--- 8< py_main ------------------------------
    #!/usr/bin/env python

    import sys
    sys.argv.pop(0)

    try:
        execfile
    except NameError:
        def execfile(file_name, globals):
            with open(file_name) as fh:
                script = fh.read()
            exec(fh, globals)

    module = {}
    execfile(sys.argv[0], module)
    module['main']()
---------------------------------------------

Put the above somewhere in your path (e.g. /usr/local/bin), make it executable, and then instead of shebanging your
scripts with `/usr/local/bin/python` you can use `/usr/local/bin/py_main`, which will load and execute the script,
calling script.main as its last act.

--
~Ethan~

[toc] | [prev] | [next] | [standalone]


#81789

FromChris Angelico <rosuav@gmail.com>
Date2014-12-02 12:15 +1100
Message-ID<mailman.16481.1417482930.18130.python-list@python.org>
In reply to#80626
On Tue, Dec 2, 2014 at 11:45 AM, Ethan Furman <ethan@stoneleaf.us> wrote:
> Put the above somewhere in your path (e.g. /usr/local/bin), make it executable, and then instead of shebanging your
> scripts with `/usr/local/bin/python` you can use `/usr/local/bin/py_main`, which will load and execute the script,
> calling script.main as its last act.

Be aware that this trick (shebanging to a script rather than a binary)
isn't specified by the POSIX standard. It works on Linux, but I don't
know about other systems. It's a great trick, though. I once had
shebangs chained something like three or four levels deep.

ChrisA

[toc] | [prev] | [next] | [standalone]


#81797

FromEthan Furman <ethan@stoneleaf.us>
Date2014-12-02 02:17 -0800
Message-ID<mailman.16490.1417515442.18130.python-list@python.org>
In reply to#80626

[Multipart message — attachments visible in raw view] — view raw

On 12/01/2014 05:15 PM, Chris Angelico wrote:
> On Tue, Dec 2, 2014 at 11:45 AM, Ethan Furman wrote:
>>
>> Put the above somewhere in your path (e.g. /usr/local/bin), make it executable, and then instead of shebanging your
>> scripts with `/usr/local/bin/python` you can use `/usr/local/bin/py_main`, which will load and execute the script,
>> calling script.main as its last act.
> 
> Be aware that this trick (shebanging to a script rather than a binary)
> isn't specified by the POSIX standard. It works on Linux, but I don't
> know about other systems. 

Ah, thanks for that!

--
~Ethan~

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.python


csiph-web