Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #60383
| From | Rotwang <sg552@hotmail.co.uk> |
|---|---|
| Newsgroups | comp.lang.python |
| Subject | Re: Method chaining |
| Date | 2013-11-24 15:01 +0000 |
| Organization | A noiseless patient Spider |
| Message-ID | <l6t4d3$fvs$1@dont-email.me> (permalink) |
| References | <528f3f4e$0$29992$c3e8da3$5496439d@news.astraweb.com> <l6r13t$ioa$1@dont-email.me> <52920cde$0$29993$c3e8da3$5496439d@news.astraweb.com> |
On 24/11/2013 14:27, Steven D'Aprano wrote:
> On Sat, 23 Nov 2013 19:53:32 +0000, Rotwang wrote:
>
>> On 22/11/2013 11:26, Steven D'Aprano wrote:
>>> A frequently missed feature is the ability to chain method calls:
> [...]
>>> chained([]).append(1).append(2).append(3).reverse().append(4) =>
>>> returns [3, 2, 1, 4]
>>
>> That's pretty cool. However, I can imagine it would be nice for the
>> chained object to still be an instance of its original type.
>
> Why?
Well, if one intends to pass such an object to a function that does
something like this:
def f(obj):
if isinstance(obj, class1):
do_something(obj)
elif isinstance(obj, class2):
do_something_else(obj)
then
>>> f(chained(obj).method1().method2())
looks nicer than
>>> f(chained(obj).method1().method2().obj)
and usually still works with the version of chained I posted last night.
This isn't a wholly hypothetical example, I have functions in my own
software that perform instance checks and that I often want to pass
objects that I've just mutated several times.
> During the chained call, you're only working with the object's own
> methods, so that shouldn't matter. Even if a method calls an external
> function with self as an argument, and the external function insists on
> the original type, that doesn't matter because the method sees only the
> original (wrapped) object, not the chained object itself.
>
> In other words, in the example above, each of the calls to list.append
> etc. see only the original list, not the chained object.
>
> The only time you might care about getting the unchained object is at the
> end of the chain. This is where Ruby has an advantage, the base class of
> everything has a method useful for chaining methods, Object.tap, where in
> Python you either keep working with the chained() wrapper object, or you
> can extract the original and discard the wrapper.
>
>
>> How about something like this:
>>
>> def getr(self, name):
>> obj = super(type(self), self).__getattribute__(name)
>
> I don't believe you can call super like that. I believe it breaks when
> you subclass the subclass.
Yes. I don't know what I was thinking with the various super calls I
wrote last night, apart from being buggy they're completely unnecessary.
Here's a better version:
class dummy:
pass
def initr(self, obj):
object.__setattr__(self, '__obj', obj)
def getr(self, name):
try:
return object.__getattribute__(self, name)
except AttributeError:
return getattr(self.__obj, name)
def methr(method):
def cmethod(*args, **kwargs):
try:
args = list(args)
self = args[0]
args[0] = self.__obj
except (IndexError, AttributeError):
self = None
result = method(*args, **kwargs)
return self if result is None else result
try:
cmethod.__qualname__ = method.__qualname__
except AttributeError:
pass
return cmethod
class chained(type):
typedict = {}
def __new__(cls, obj):
if isinstance(type(obj), chained):
return obj
if type(obj) not in cls.typedict:
dict = {}
for t in reversed(type(obj).__mro__):
dict.update({k: methr(v) for k, v in t.__dict__.items()
if callable(v) and k != '__new__'})
dict.update({'__init__': initr, '__getattribute__': getr})
cls.typedict[type(obj)] = type.__new__(cls, 'chained%s'
% type(obj).__name__, (dummy, type(obj)), dict)
return cls.typedict[type(obj)](obj)
Back to comp.lang.python | Previous | Next — Previous in thread | Find similar | Unroll thread
Method chaining Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-11-22 11:26 +0000
Re: Method chaining Chris Angelico <rosuav@gmail.com> - 2013-11-22 22:44 +1100
Re: Method chaining Peter Otten <__peter__@web.de> - 2013-11-22 13:08 +0100
Re: Method chaining Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-11-22 14:26 +0000
Re: Method chaining Peter Otten <__peter__@web.de> - 2013-11-22 16:20 +0100
Re: Method chaining Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-11-22 16:26 +0000
Re: Method chaining Wolfgang Maier <wolfgang.maier@biologie.uni-freiburg.de> - 2013-11-22 16:52 +0000
Re: Method chaining Wolfgang Maier <wolfgang.maier@biologie.uni-freiburg.de> - 2013-11-22 17:55 +0000
Re: Method chaining Antoon Pardon <antoon.pardon@rece.vub.ac.be> - 2013-11-22 16:38 +0100
Re: Method chaining Laszlo Nagy <gandalf@shopzeus.com> - 2013-11-23 17:08 +0100
Re: Method chaining Terry Reedy <tjreedy@udel.edu> - 2013-11-22 07:34 -0500
Re: Method chaining Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-11-22 14:30 +0000
Re: Method chaining Rotwang <sg552@hotmail.co.uk> - 2013-11-23 19:53 +0000
Re: Method chaining Rotwang <sg552@hotmail.co.uk> - 2013-11-24 00:28 +0000
Re: Method chaining Rotwang <sg552@hotmail.co.uk> - 2013-11-24 00:43 +0000
Re: Method chaining Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-11-24 14:27 +0000
Re: Method chaining Rotwang <sg552@hotmail.co.uk> - 2013-11-24 15:01 +0000
csiph-web