(original) (raw)

On Wed, Oct 4, 2017 at 8:07 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On 3 October 2017 at 03:13, Koos Zevenhoven <k7hoven@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):
contextmanager.\_\_exit\_\_()
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

--
+ Koos Zevenhoven + http://twitter.com/k7hoven +