diff options
author | jdemeyer <jdemeyer@cage.ugent.be> | 2018-04-13 12:22:46 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2018-04-13 12:22:46 (GMT) |
commit | 23ab5ee667a9b29014f6f7f01797c611f63ff743 (patch) | |
tree | 9e55defd8958fab8dad3a865d70447eca9633fc5 | |
parent | ffa2c3e2c40acae07aca5b77f2c0e8c14a00438d (diff) | |
download | cpython-23ab5ee667a9b29014f6f7f01797c611f63ff743.zip cpython-23ab5ee667a9b29014f6f7f01797c611f63ff743.tar.gz cpython-23ab5ee667a9b29014f6f7f01797c611f63ff743.tar.bz2 |
bpo-33265: use an actual method instead of a method-like function in ExitStack (GH-6456)
`MethodType` has the exact semantics that `ExitStack` needs,
so we can avoid creating a Python level closure.
-rw-r--r-- | Lib/contextlib.py | 11 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2018-04-13-08-12-50.bpo-33265.KPQRk0.rst | 2 |
2 files changed, 5 insertions, 8 deletions
diff --git a/Lib/contextlib.py b/Lib/contextlib.py index 1ff8cdf..1a58b50 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -4,6 +4,7 @@ import sys import _collections_abc from collections import deque from functools import wraps +from types import MethodType __all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext", "AbstractContextManager", "AbstractAsyncContextManager", @@ -373,9 +374,7 @@ class _BaseExitStack: @staticmethod def _create_exit_wrapper(cm, cm_exit): - def _exit_wrapper(exc_type, exc, tb): - return cm_exit(cm, exc_type, exc, tb) - return _exit_wrapper + return MethodType(cm_exit, cm) @staticmethod def _create_cb_wrapper(callback, *args, **kwds): @@ -443,7 +442,6 @@ class _BaseExitStack: def _push_cm_exit(self, cm, cm_exit): """Helper to correctly register callbacks to __exit__ methods.""" _exit_wrapper = self._create_exit_wrapper(cm, cm_exit) - _exit_wrapper.__self__ = cm self._push_exit_callback(_exit_wrapper, True) def _push_exit_callback(self, callback, is_sync=True): @@ -535,9 +533,7 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager): @staticmethod def _create_async_exit_wrapper(cm, cm_exit): - async def _exit_wrapper(exc_type, exc, tb): - return await cm_exit(cm, exc_type, exc, tb) - return _exit_wrapper + return MethodType(cm_exit, cm) @staticmethod def _create_async_cb_wrapper(callback, *args, **kwds): @@ -596,7 +592,6 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager): """Helper to correctly register coroutine function to __aexit__ method.""" _exit_wrapper = self._create_async_exit_wrapper(cm, cm_exit) - _exit_wrapper.__self__ = cm self._push_exit_callback(_exit_wrapper, False) async def __aenter__(self): diff --git a/Misc/NEWS.d/next/Library/2018-04-13-08-12-50.bpo-33265.KPQRk0.rst b/Misc/NEWS.d/next/Library/2018-04-13-08-12-50.bpo-33265.KPQRk0.rst new file mode 100644 index 0000000..523ceb9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-13-08-12-50.bpo-33265.KPQRk0.rst @@ -0,0 +1,2 @@ +``contextlib.ExitStack`` and ``contextlib.AsyncExitStack`` now use a method +instead of a wrapper function for exit callbacks. |