[Python-Dev] Inheritance vs composition in backcompat (PEP521)

Guido van Rossum guido at python.org
Mon Oct 2 17:02:34 EDT 2017


On Mon, Oct 2, 2017 at 10:13 AM, Koos Zevenhoven <k7hoven at gmail.com> wrote:

> Hi all, It was suggested that I start a new thread, because the other
> thread drifted away from its original topic. So here, in case someone is
> interested:
>
> On Oct 2, 2017 17:03, "Koos Zevenhoven <k7hoven at gmail.com> wrote:
>
> On Mon, Oct 2, 2017 at 6:42 AM, Guido van Rossum <guido at python.org> wrote:
>
> On Sun, Oct 1, 2017 at 1:52 PM, Koos Zevenhoven <k7hoven at gmail.com> wrote:
>
> On Oct 1, 2017 19:26, "Guido van Rossum" <guido at python.org> wrote:
>
> Your PEP is currently incomplete. If you don't finish it, it is not even a
> contender. But TBH it's not my favorite anyway, so you could also just
> withdraw it.
>
>
> I can withdraw it if you ask me to, but I don't want to withdraw it
> without any reason. I haven't changed my mind about the big picture. OTOH,
> PEP 521 is elegant and could be used to implement PEP 555, but 521 is
> almost certainly less performant and has some problems regarding context
> manager wrappers that use composition instead of inheritance.
>
>
> It is my understanding that PEP 521 (which proposes to add optional
> __suspend__ and __resume__ methods to the context manager protocol, to be
> called whenever a frame is suspended or resumed inside a `with` block) is
> no longer a contender because it would be way too slow. I haven't read it
> recently or thought about it, so I don't know what the second issue you
> mention is about (though it's presumably about the `yield` in a context
> manager implemented using a generator decorated with
> `@contextlib.contextmanager`).
>
>
> ​Well, it's not completely unrelated to that. The problem I'm talking
> about is perhaps most easily seen from a simple context manager wrapper
> that uses composition instead of inheritance:
>
> class Wrapper:
>     def __init__(self):
>         self._wrapped = SomeContextManager()
>
>     def __enter__(self):
>         print("Entering context")
>         return self._wrapped.__enter__()
>
>     def __exit__(self):
>         self._wrapped.__exit__()
>         print("Exited context")
>
>
> Now, if the wrapped contextmanager becomes a PEP 521 one with __suspend__
> and __resume__, the Wrapper class is broken, because it does not respect
> __suspend__ and __resume__. So actually this is a backwards compatiblity
> issue.
>
>
Why is it backwards incompatible? I'd think that without PEP 521 it would
be broken in exactly the same way because there's no __suspend__/__resume__
at all.


> But if the wrapper is made using inheritance, the problem goes away:
>
>
> class Wrapper(SomeContextManager):
>     def __enter__(self):
>         print("Entering context")
>         return super().__enter__()
>
>     def __exit__(self):
>         super().__exit__()
>         print("Exited context")
>
>
> Now the wrapper cleanly inherits the new optional __suspend__ and
> __resume__ from the wrapped context manager type.
>
>
In any case this is completely academic because PEP 521 is not going to
happen. Nathaniel himself has said so (I think in the context of discussing
PEP 550).

-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20171002/a4705240/attachment.html>


More information about the Python-Dev mailing list