9

In Python 2, why are instances of old style classes still instances of object even when they do not explicitly inherit from object?

class OldClass:
    pass

>>> isinstance(OldClass(), object)
True

Before testing this, I would have concluded that isinstance(x, object) == True would imply that x is an instance of a subclass of object and thus an instance of a new style class, but it appears that all objects in Python 2 are instances of object (yes, I know how obvious that sounds).


Digging around further, I found some other seemingly odd behavior:

>>> issubclass(OldClass, object)
False

I was under the impression that isinstance(x, SomeClass) is virtually equivalent to issubclass(x.__class__, SomeClass), but apparently I'm missing something.

Markus Meskanen
  • 19,939
  • 18
  • 80
  • 119
Billy
  • 5,179
  • 2
  • 27
  • 53
  • 4
    @Jean-FrançoisFabre How does that answer the question at all? – Markus Meskanen Jun 15 '17 at 11:46
  • the answer to that particular question (besides the link to the original question) is: because it's been designed that way. – Jean-François Fabre Jun 15 '17 at 11:47
  • It's literally just that old style classes implicitly inherited object, the new ones just change that to an explicit inherit. – Keef Baker Jun 15 '17 at 11:49
  • 2
    @Jean-FrançoisFabre Because it's designed that way", what?? This question can be answered properly by someone who knows how old style classes work. If an instance of `Foo` is also an instance of `object`, how does "it was designed that way" answer why `Foo` isn't a subclass of `object`? – Markus Meskanen Jun 15 '17 at 11:49
  • 1
    @KeefBaker If old style classes implicitly inherited object, then why `issubclass(OldClass, object) == False` in OP's example? – Markus Meskanen Jun 15 '17 at 11:50
  • Because I can't read. – Keef Baker Jun 15 '17 at 11:51
  • Fair enough :D @KeefBaker – Markus Meskanen Jun 15 '17 at 11:51
  • 2
    Everything is an instance of `object`, but old-style classes have a divided implementation. The class itself is an instance of `classobj`, and its instances are `instance` objects. – Eryk Sun Jun 15 '17 at 11:51
  • 2
    Sorry, I can't find the answer to this question at that link, it simply contrasts two different functions (which I understand: `isinstance` expects an object as the first argument, `issubclass` expects a class/type as the first argument) – Billy Jun 15 '17 at 11:52
  • 4
    I agree that this is not a good 'duplicate'. Should probably be re-opened. – Dylan Meeus Jun 15 '17 at 11:52
  • I've closed the question and I'm not reopening it (because everytime I did that someone answered the exact thing in the duplicate and that was closed as duplicate anyway). You can vote to reopen / rely on some python gold badge owner to reopen it. – Jean-François Fabre Jun 15 '17 at 11:53
  • @eryksun: Can you please reopen and explain the "divided implementation" in an answer? – Billy Jun 15 '17 at 11:54
  • @eryksun do you think you can reply to that particular question without being redundant to the duplicate link? if so you have the power to do so (I don't want to be the bad guy here) – Jean-François Fabre Jun 15 '17 at 11:54
  • 1
    @Jean-FrançoisFabre The other question answers "Because you're using an old style class, use new style class instead", while this question clearly acknowledges the usage of an old style class, and asks for the more technical details behind it, to find out why this behavior happens. By the definition of `isinstance()` and `issubclass`, there should always be `issubclass(Foo, Bar) == isinstance(Foo(), Bar)`, but this isn't the case here, which is why OP asked the question. – Markus Meskanen Jun 15 '17 at 11:57
  • @MarkusMeskanen I think you stopped reading after the accepted answer. The other answer (with 30+ votes) is much better and I think it answers the current question. The fact that noone reopened it yet is another indication. – Jean-François Fabre Jun 15 '17 at 12:00
  • 2
    That answer doesn't answer this question either. It's about the old-style *classes* being instances of `object` but not subclasses of it. This question is about why an *instance* of an old style class is also an instance of `object`, which makes absolutely no sense, since an old style class is not a subclass of `object`. – Markus Meskanen Jun 15 '17 at 12:10
  • 2
    Both `issubclass(OldClass, OtherOldClass)` and `isinstance(OldClass(), OldClass)` are special cased. For the latter it has to get the `__class__` attribute from the `OldClass()` instance to check the special-cased form of `issubclass`. We can get into the details of the implementation in CPython, but I think it suffices to know that there's no type-based link between `OldClass` and `OldClass()`. It wasn't until Python 2.2 that types and classes were unified such that `type(NewClass()) is NewClass`. – Eryk Sun Jun 15 '17 at 12:23
  • 2
    If what eryksun said is true, then it should be an answer to this question. I don't see anything remotely like that in the other question. Please reopen already @Jean-FrançoisFabre – Markus Meskanen Jun 15 '17 at 12:25
  • 1
    @eryksun: since the question is open again, you should turn your comment as an answer. – Jean-François Fabre Jun 15 '17 at 12:35
  • 3
    Someone *please* answer this question. This comment chain is getting ridiculous. – idjaw Jun 15 '17 at 12:47
  • @MarkusMeskanen can you explain why the [tag:python-internals] *is* applicable? The question isn't about the internal working of the interpreter, and it's sufficient to know the Python 2 data model to answer it. – vaultah Jun 15 '17 at 13:09
  • @vaultah *"How does Python work underneath the hood?"* is the definition for `python-internals`, isn't this question about that? Python seems to be doing something weird with `issubclass()` and `isinstance()` that doesn't match to what a layman would expect, and requires further investigation on how exactly old-style classes work with `issubclass()` and `isinstance()`. I may have gotten the tag wrong tho, enlighten me if that's the case – Markus Meskanen Jun 15 '17 at 13:18
  • 1
    As you can see, the question was reopened, then closed as duplicate ... again. At some point, you have to let it go: this is a rethorical question on python 2.x, just for curiosity but not very useful in the real life. – Jean-François Fabre Jun 15 '17 at 14:03
  • 1
    Thanks - the new duplicate mark clears it up. I don't know why that didn't come up when I first searched. – Billy Jun 15 '17 at 14:29

0 Answers0