My intuition differs from Steven's here. But that's fine. In any case, my simple implementation of RingBuffer in this thread avoids either rebinding methods or changing .__class__.
And yes, of course collections.deque is better than any of these implementations. I was just trying to show that any such magic is unlikely to be necessary... and in particular that the recipe given as an example doesn't show it is. But still, you REALLY want your `caterpillar = Caterpillar()` to become something of type "Butterfly" later?! Obviously I understand the biological metaphor. But I'd much rather have an API that provided me with .has_metamorphosed() then have to look for the type as something new. Btw. Take a look at Alex' talk with Anna at PyCon 2015. They discuss various "best practices" that have been superseded by improved language facilities. They don't say anything about this "mutate the __class__ trick", but I somehow suspect he'd put that in that category. On Sun, Oct 18, 2015 at 6:47 PM, Steven D'Aprano <st...@pearwood.info> wrote: > On Sun, Oct 18, 2015 at 05:35:14PM -0700, David Mertz wrote: > > > In any case, redefining a method in a certain situation feels a lot less > > magic to me than redefining .__class__ > > That surprises me greatly. As published in the Python Cookbook[1], there > is a one-to-one correspondence between the methods used by an object and > its class. If you want to know what instance.spam() method does, you > look at the class type(instance) or instance.__class__, and read the > source code for spam. > > With your suggestion of re-defining the methods on the fly, you no > longer have that simple relationship. If you want to know what > instance.spam() method does, first you have to work out what it actually > is, which may not be that easy. In the worst case, it might not be > possible at all: > > class K: > def method(self): > if condition: > self.method = random.choice([lambda self: ..., > lambda self: ..., > lambda self: ...]) > > > Okay, that's an extreme example, and one can write bad code using any > technique. But even with a relatively straight-forward version: > > def method(self): > if condition: > self.method = self.other_method > > > I would classify "change the methods on the fly" as self-modifying code, > which strikes me as much more hacky and hard to maintain than something > as simple as changing the __class__ on the fly. > > Changing the __class__ is just a straight-forward metamorphosis: what > was a caterpillar, calling methods defined in the Caterpillar class, is > now a butterfly, calling methods defined in the Butterfly class. > > (The only change I would make from the published recipe would be to make > the full Ringbuffer a subclass of the regular one, so isinstance() tests > would work as expected. But given that the recipe pre-dates the > wide-spread use of isinstance, the author can be forgiven for not > thinking of that.) > > If changing the class on the fly is a metamorphosis, then it seems to me > that self-modifying methods are like something from The Fly, where a > horrible teleporter accident grafts body parts and DNA from one object > into another object... or at least *repurposes* existing methods, so > that what was your leg is now your arm. > > I've done that, and found it harder to reason about than the > alternative: > > "okay, the object is an RingBuffer, but is the append method the > RingBuffer.append method or the RingBuffer.full_append method?" > > versus > > "okay, the object is a RingBuffer, therefore the append method is the > RingBuffer.append method". > > > In my opinion, the only tricky thing about the metamorphosis tactic is > that: > > obj = Caterpillar() > # later > assert type(obj) is Caterpillar > > may fail. You need a runtime introspection to see what the type of obj > actually is. But that's not exactly unusual: if you consider Caterpillar > to be a function rather than a class constructor (a factory perhaps?), > then it's not that surprising that you can't know what *specific* > type a function returns until runtime. There are many functions with > polymorphic return types. > > > > > > [1] The first edition of the Cookbook was edited by Python luminaries > Alex Martelli and David Ascher, so this recipe has their stamp of > approval. This isn't some dirty hack. > > > -- > Steve > _______________________________________________ > Python-Dev mailing list > Python-Dev@python.org > https://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > https://mail.python.org/mailman/options/python-dev/mertz%40gnosis.cx > -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th.
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com