]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-33265: use an actual method instead of a method-like function in ExitStack (GH...
authorjdemeyer <jdemeyer@cage.ugent.be>
Fri, 13 Apr 2018 12:22:46 +0000 (14:22 +0200)
committerNick Coghlan <ncoghlan@gmail.com>
Fri, 13 Apr 2018 12:22:46 +0000 (22:22 +1000)
`MethodType` has the exact semantics that `ExitStack` needs,
so we can avoid creating a Python level closure.

Lib/contextlib.py
Misc/NEWS.d/next/Library/2018-04-13-08-12-50.bpo-33265.KPQRk0.rst [new file with mode: 0644]

index 1ff8cdf1cecf8f4319475236b344f31baf34dfed..1a58b509f67c2818403c2be4951585a037bf0e3d 100644 (file)
@@ -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 (file)
index 0000000..523ceb9
--- /dev/null
@@ -0,0 +1,2 @@
+``contextlib.ExitStack`` and ``contextlib.AsyncExitStack`` now use a method
+instead of a wrapper function for exit callbacks.