This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: atexit and execution order
Type: Stage: resolved
Components: Documentation Versions: Python 3.2, Python 3.3, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: eric.araujo Nosy List: benjamin.peterson, eric.araujo, giampaolo.rodola, meador.inge, neologix, pitrou, python-dev
Priority: normal Keywords: needs review, patch

Created on 2010-09-07 10:27 by giampaolo.rodola, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
doc-atexit-order-undefined.diff eric.araujo, 2011-06-10 17:04 review
Messages (15)
msg115747 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2010-09-07 10:27
import atexit

@atexit.register
def goodbye1():
    print(1)
    
@atexit.register
def goodbye2():
    print(2)

The code above prints:

2
1

...that is, the last registered function is executed first.
Wouldn't the contrary be better?
msg115749 - (view) Author: Skip Montanaro (skip.montanaro) * (Python triager) Date: 2010-09-07 10:59
I'm sure you can craft cases where one order is preferable to
another, but I don't think you can make the case in general
that first in, first out is preferable to last in, first out,
or any other ordering of exit functions.
msg115756 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2010-09-07 13:20
I think it's not a matter of "preferable" but "most expected" and I see FIFO as the most expected behavior in this case.
msg115764 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-09-07 14:20
LIFO looks preferable if you want your setup/teardown code to be properly nested (that is, if I set up A before B, I want B to be torn down before A).
msg115769 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2010-09-07 14:59
It seems to me that atexit is simple by design: It registers callables that do one thing, period. If you have dependencies in your cleanup code, you should write a function doing the Right Thing™ and register that. This keeps the implementation simple, otherwise we’d have to debate LIFO vs. FIFO, adding an argument to register vs. exposing the list of callables, etc.

If you agree, I could make a patch to make the docs more explicit about atexit’s simplicity and lack of guarantee about run order.
msg115790 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2010-09-07 18:07
I don't think the order should be defined.
msg115791 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2010-09-07 18:37
Ok, I'll shut up then. =)

> If you agree, I could make a patch to make the docs more explicit about 
> atexit’s simplicity and lack of guarantee about run order.

Sure, go ahead.
msg116225 - (view) Author: Meador Inge (meador.inge) * (Python committer) Date: 2010-09-12 18:49
I agree with Antoine's LIFO comment.  Also, FWIW, the C standard library behaves in a LIFO manner as well (C99 spec - 7.20.4.3 clause 3):

"First, all functions registered by the atexit function are called, in the reverse order of their registration,253) except that a function is called after any previously registered functions that had already been called at the time it was registered. If, during the call to any such function, a call to the longjmp function is made that would terminate the call to the registered function, the behavior is undefined."
msg138113 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2011-06-10 17:04
Here’s a patch.
msg138123 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2011-06-10 17:49
> I don't think the order should be defined.

I disagree.
The C standard explicitely states that the functions are called in LIFO order (which is the natural order in this case).

The current implementation guarantees LIFO order, I think it should be documented.
msg141393 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2011-07-29 16:11
New changeset e37fa30c4be4 by Éric Araujo in branch '3.2':
Document that atexit execution order is undefined (#9788)
http://hg.python.org/cpython/rev/e37fa30c4be4
msg141396 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2011-07-29 16:13
New changeset df415bfbb652 by Éric Araujo in branch '2.7':
Document that atexit execution order is undefined (#9788)
http://hg.python.org/cpython/rev/df415bfbb652
msg141397 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2011-07-29 16:19
Given Benjamin and Giampaolo’s support, I committed my patch, so that at least the current behavior is documented.  I personally have no opinion on LIFO vs. FIFO vs. undefined; I just think that the atexit module is not a wrapper around C’s atexit, and as such not bound by the same rules, and undefined sounds fine.  If you feel very strongly about that, then please follow up on python-dev.
msg141409 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2011-07-29 19:33
Thanks. After all, I think that "keeping atexit simple" is the best solution and a doc adjustement is just fine.
msg164964 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2012-07-08 04:37
Reopened as #15233.
History
Date User Action Args
2022-04-11 14:57:06adminsetgithub: 53997
2012-07-08 04:37:52eric.araujosetmessages: + msg164964
2011-07-29 19:33:19giampaolo.rodolasetmessages: + msg141409
2011-07-29 16:19:15eric.araujosetstatus: open -> closed
resolution: fixed
messages: + msg141397

stage: patch review -> resolved
2011-07-29 16:13:47python-devsetmessages: + msg141396
2011-07-29 16:11:12python-devsetnosy: + python-dev
messages: + msg141393
2011-06-10 17:49:32neologixsetnosy: + neologix
messages: + msg138123
2011-06-10 17:04:31eric.araujosetfiles: + doc-atexit-order-undefined.diff
versions: + Python 3.3, - Python 3.1
messages: + msg138113

keywords: + needs review, patch
resolution: accepted -> (no value)
stage: needs patch -> patch review
2011-03-19 19:11:02skip.montanarosetnosy: - skip.montanaro
2010-09-12 18:49:36meador.ingesetnosy: + meador.inge
messages: + msg116225
2010-09-08 00:56:05eric.araujosetversions: + Python 3.1, Python 2.7
nosy: skip.montanaro, pitrou, giampaolo.rodola, benjamin.peterson, eric.araujo
assignee: eric.araujo
components: + Documentation, - Library (Lib)
resolution: accepted
stage: needs patch
2010-09-07 18:37:47giampaolo.rodolasetmessages: + msg115791
2010-09-07 18:07:09benjamin.petersonsetnosy: + benjamin.peterson
messages: + msg115790
2010-09-07 14:59:10eric.araujosetmessages: + msg115769
2010-09-07 14:20:39pitrousetnosy: + pitrou
messages: + msg115764
2010-09-07 13:20:47giampaolo.rodolasetmessages: + msg115756
2010-09-07 11:59:43eric.araujosetnosy: + eric.araujo
2010-09-07 10:59:17skip.montanarosetnosy: + skip.montanaro
messages: + msg115749
2010-09-07 10:27:12giampaolo.rodolacreate