atexit.register does not return the registered function. IMHO, it should.

prouleau001 at prouleau001 at
Thu Nov 16 17:03:48 CET 2006

Hi all!

Since that the decorator syntax is upon us, I think it would be good if
atexit.register() was returning the function passed as argument.  This
simple change to the library would solve a problem with the use of
atexit.register as a decorator (and I can't think of any use case where
this change would break any code).

I describe the problem in the following text.

Problem using atexit.register as a decorator

In his April 2005 article titled `Python 2.4 Decorators: Reducing code
duplication and consolidating knowledge`_ , Phillip Eby describes how
you can use `atexit.register()`_ from the standard Python library. He
shows how to use the decorator syntax to register a function that will
execute at program termination. Here is how it goes::

  def goodbye():
      print "Goodbye, terminating..."

However, there is one fundamental problem with this: atexit.register()
returns None. Since the above code corresponds to::

  def goodbye():
      print "Goodbye, terminating..."
  goodbye = atexit.register(goodbye)

the code registers goodbye but right after it binds goodbye to None!
You can see this in the following session::

    >>> import atexit
    >>> @atexit.register
    ... def goodbye():
    ...   print "Goodbye, terminating..."
    >>> goodbye()
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    TypeError: 'NoneType' object is not callable
    >>> goodbye
    >>> type(goodbye)
    <type 'NoneType'>

There is two solutions to this problem:

  1. Use another function to register and decorate.
  2. Change atexit.register() in the Python library so that
     it returns the function it registers.

Solution 1 can be implemented right away::

  def atexit_register(fct):
      return fct

  def goodbye2():
      print "Goodbye 2!!"

and it works: it registers the function for execution at termination
but leaves goodbye2 callable::

  >>> def atexit_register(fct):
  ...   atexit.register(fct)
  ...   return fct
  >>> @atexit_register
  ... def goodbye2():
  ...   print "Goodbye 2!!"
  >>> goodbye2()
  Goodbye 2!!
  >>> goodbye2
  <function goodbye2 at 0x009DD930>

.. References

.. _atexit.register():
.. _Python 2.4 Decorators\: Reducing code duplication and consolidating

More information about the Python-list mailing list