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

Koos Zevenhoven k7hoven at gmail.com
Wed Oct 4 06:22:44 EDT 2017

On Wed, Oct 4, 2017 at 8:07 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:

> On 3 October 2017 at 03:13, Koos Zevenhoven <k7hoven at gmail.com> wrote:
> > 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.
> This is a known problem, and one of the main reasons that having a
> truly transparent object proxy like
> https://wrapt.readthedocs.io/en/latest/wrappers.html#object-proxy as
> part of the standard library would be highly desirable.
This is barely related to the problem I describe. The wrapper is not
supposed to pretend to *be* the underlying object. It's just supposed to
extend its functionality.

Maybe it's just me, but using a transparent object proxy for this sounds
like someone trying to avoid inheritance for no reason and at any cost.
Inheritance probably has faster method access, and makes it more obvious
what's going on:

def Wrapper(contextmanager):
    class Wrapper(type(contextmanager)):
        def __enter__(self):
            print("Entering context")
            return contextmanager.__enter__()

        def __exit__(self):
            print("Exited context")
    return Wrapper()

A wrapper based on a transparent object proxy is just a non-transparent
replacement for inheritance. Its wrapper nature is non-transparent because
it pretends to `be` the original object, while it's actually a wrapper.

But an object cannot `be` another object as long as the `is` operator won't
return True. And any straightforward way to implement that would add
performance overhead for normal objects.

I do remember sometimes wanting a transparent object proxy. But not for
normal wrappers. But I don't think I've gone as far as looking for a
library to do that, because it seems that you can only go half way anyway.


+ Koos Zevenhoven + http://twitter.com/k7hoven +
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20171004/eb542c25/attachment.html>

More information about the Python-Dev mailing list