4 ms·
Nice write-up! Coincidentally, I wrote on the same topic, also in python just a few days ago [1] I came to largely the same conclusions, but instead of forward
by bgschiller 7y ago
Nice write-up! Coincidentally, I wrote on the same topic, also in python just a few days ago [1]
I came to largely the same conclusions, but instead of forwardable, I wrote a new library called superdelegate that is, IMO, more explicit [2]
1: https://brianschiller.com/blog/2019/05/03/two-sorted-lists https://brianschiller.com/blog/2019/05/03/two-sorted-lists
2: https://github.com/bgschiller/superdelegate https://github.com/bgschiller/superdelegate
- seishan 7y agoThat was a great read that was easy to digest. Thanks for writing this up!
- btown 7y agoAlternately, if you want to just delegate everything, you can subclass wrapt.ObjectProxy https://wrapt.readthedocs.io/en/latest/wrappers.html#object-proxy https://wrapt.readthedocs.io/en/latest/wrappers.html#object-... Python is scary sometimes. If it looks like a duck and quacks like a duck and isinstance(duck), it might be an alien masquerading as a duck using metaclasses to accomplish these feats. But with this craziness comes the ability to make a transparent runtime proxy to just about anything in Python, and do so recursively e.g. to track all uses of an object hierarchy.
- bgschiller 7y agoI think I'm confused. If you want to delegate _everything_, why not just actually use inheritance? Or even the object itself. What's an example of when you would want an ObjectProxy? Definitely agree about metaclass magic being a blessing and a curse. That superdelegate library was fun to write and uses a metaclass to make the API pleasant.
- btown 7y agoIf you don't know what you're going to need to wrap (heck, it might be something with methods implemented with native code), but you want to override or intercept a certain subset of calls, then composition/delegation is really the only thing you can do. It's significantly more stable than trying to find the class of an arbitrary object at runtime, create a subclass of it, and try to copy the state of the original object. For instance, I've seen instrumentation libraries monkey-patch database cursors with wrappers around those cursors, so the library can detect usage of the cursor without changing its behavior. Django itself has a LazyObject class, which operates similarly to an ObjectProxy but only evaluates its wrapped initializer when one of its properties is accessed: https://docs.djangoproject.com/en/2.2/_modules/django/utils/functional/ https://docs.djangoproject.com/en/2.2/_modules/django/utils/... And I'm using wrapt in a project (which I hope to open source) where, by recursively wrapping the return value of every __getitem__ and __getattr__ with a properly-bookkept proxy object, you can see what subgraph of a complicated object hierarchy was actually used by a function call (say, the rendering of a Django or Jinja template). Possibilities of such a transformation are endless!
- zmmmmm 7y agoYou don't have to sacrifice type safety, that's a python problem. Other languages (eg: Groovy) accomplish the same thing in a type-safe way (see @Delegate annotation [1]). http://docs.groovy-lang.org/2.4.9/html/gapi/groovy/lang/Delegate.html http://docs.groovy-lang.org/2.4.9/html/gapi/groovy/lang/Dele...
- skocznymroczny 7y agoIn D some of that can be done with a Proxy mixin https://dlang.org/phobos/std_typecons.html#Proxy https://dlang.org/phobos/std_typecons.html#Proxy
- jnwatson 7y agoI like it. I run into this use case all the time.