[Python-Dev] type(obj) vs. obj.class (original) (raw)

David Mertz mertz at gnosis.cx
Sun Oct 18 22:12:34 EDT 2015


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 <steve at 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.othermethod 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.fullappend 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 at 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. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.python.org/pipermail/python-dev/attachments/20151018/62cfd057/attachment.html>



More information about the Python-Dev mailing list