python / cpython

The Python programming language
https://www.python.org
Other
63.55k stars 30.45k forks source link

atexit.register does not return the registered function. #44239

Closed 9ef3482a-82ee-4013-bda4-50f5956df0ec closed 18 years ago

9ef3482a-82ee-4013-bda4-50f5956df0ec commented 18 years ago
BPO 1597824
Nosy @birkenfeld

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields: ```python assignee = 'https://github.com/birkenfeld' closed_at = created_at = labels = ['library'] title = 'atexit.register does not return the registered function. ' updated_at = user = 'https://bugs.python.org/pierrerouleau' ``` bugs.python.org fields: ```python activity = actor = 'georg.brandl' assignee = 'georg.brandl' closed = True closed_date = None closer = None components = ['Library (Lib)'] creation = creator = 'pierre_rouleau' dependencies = [] files = [] hgrepos = [] issue_num = 1597824 keywords = [] message_count = 2.0 messages = ['30564', '30565'] nosy_count = 2.0 nosy_names = ['georg.brandl', 'pierre_rouleau'] pr_nums = [] priority = 'normal' resolution = 'accepted' stage = None status = 'closed' superseder = None type = None url = 'https://bugs.python.org/issue1597824' versions = ['Python 2.5'] ```

9ef3482a-82ee-4013-bda4-50f5956df0ec commented 18 years ago

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::

  @atexit.register
  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):
      atexit.register(fct)
      return fct

  @atexit_register
  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(): http://www.python.org/doc/current/lib/module-atexit.html .. _Python 2.4 Decorators\: Reducing code duplication and consolidating knowledge: http://www.ddj.com/184406073

birkenfeld commented 18 years ago

This is a reasonable request, I changed atexit.register in rev. 52764 for 2.6.