17

Can somebody explain to me why this works (in Python 2.5) :

class Foo(object):
    pass

class Bar(Foo):
    pass

print(Foo.__subclasses__())

but this doesn't :

class Foo():
    pass

class Bar(Foo):
    pass

print(Foo.__subclasses__())

The latter returns "AttributeError: class Foo has no attribute '__subclasses__'" but i'm not sure why. I know this is related to old-style vs. new-style classes but i'm not clear on why that would make this functionality unavailable.

Clarification: I'm looking to understand WHY __subclasses__() isn't available in old-style, i get that the method doesn't exist for old-style classes but I don't get what it is about new-style that makes these new functions possible.

Fraser Graham
  • 4,650
  • 4
  • 22
  • 42
  • 5
    Why does the new Microsoft Office have a ribbon bar and the old ones don't? It's just a new feature... – FogleBird May 20 '10 at 20:32
  • ok sure, but what's different about the data that's stored in my class that makes this possible, you can't blame me for wanting to know WHY something works can you? – Fraser Graham May 20 '10 at 20:40
  • 2
    Why do you assume that the lack of subclasses implies that it was not possible to implement? Why can't it just be a new feature that was never back-ported? I can't guarantee that this is the case but it seems silly to make that assumption. – FogleBird May 20 '10 at 20:45
  • if that's the answer then that's fine, i'm just curious to understand how things work – Fraser Graham May 20 '10 at 20:58

2 Answers2

34
class Foo(object):
    pass

The class above is a "new-style" class because it inherits from the object class. New-style classes provide a lot of extra framework that "old-style" classes do not have. One particular attribute of a new-style class is to be able to determine the subclasses of the class with the __subclasses__ method.

There is some good discussion about new-style classes and the __subclasses__ method which use to be completely undocumented. ( Here is an unofficial explanation from Tim Peters, though. )

"Each new-style class keeps a list of weak references to its immediate subclasses. This method returns a list of all those references still alive."

So to answer your question, the __subclasses__ functionality is not available because in your second example:

class Foo():
    pass

The old-style class Foo does not inherit from object (so it's not a new-style class) and there for does not inherit the __subclasses__ method.

Note, if you don't understand why an old-style class does not have the __subclasses__ method you could always fire up a python interpreter and do some inspection with dir

>>> class Foo(object):
...     pass
...
>>> dir(Foo.__class__)
['__abstractmethods__', '__base__', '__bases__', '__basicsize__', '__call__', '__class__', '__delattr__', '__dict__', '__dictoffset__', '__doc__', '__
eq__', '__flags__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__instancecheck__', '__itemsize__', '__le__', '__lt
__', '__module__', '__mro__', '__name__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__s
ubclasscheck__', '__subclasses__', '__subclasshook__', '__weakrefoffset__', 'mro']
>>> class Bar():
...     pass
...
>>> dir(Bar.__class__)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class Bar has no attribute '__class__'
>>> dir(Bar)
['__doc__', '__module__']
>>> dir(Foo)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '
__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
Community
  • 1
  • 1
manifest
  • 2,208
  • 16
  • 13
  • I get that is doesn't have the methods, I'm looking to understand WHY they aren't there, what makes it possible to implement __subclasses__ in a new-style that's not available in old-style – Fraser Graham May 20 '10 at 20:27
  • 1
    I think it is just a matter of it not being implemented in old-style classes, not that it couldn't have been implemented. I don't know how the subclasses method's innards work but I highly doubt that there was some fundamental language change that made this possible in new-style classes. – manifest May 20 '10 at 21:19
3

Adding to the answer above.

Python 3.0 has a separate implementation of classes. Subclassing is a feature in Python 3.0 and not Python 2.0.

So if you install python 3.x and do

class Foo():
    pass

class Bar(Foo):
    pass

print(Foo.__subclasses__())

It will not give any attribute error.

Now, the same functionality is extended to Python 2.0 classes, by inheriting "object" base class in each class definition.

So if you do in Python 2.x:

class Foo(object):
    pass

class Bar(Foo):
    pass

print(Foo.__subclasses__())

Since you are inheriting object base class in new class Foo, the 3.x style class is inherited and no attribute error comes.

But when you do in Python 2.x

class Foo():
    pass

class Bar(Foo):
    pass

print(Foo.__subclasses__())

it means, new style classes have not been inherited and since subclass is a part of new style classes, it will throw an attribute error.

So remember, if you want to extend any Python 3.x class functionality to Python 2.x, you need to inherit object class in your class definition.

Hope this helps.

Priyesh
  • 415
  • 3
  • 11
  • 8
    The third sentence of this answer is simply false. – tacaswell Feb 27 '14 at 15:19
  • Which statement are you talking about? Please elaborate. To Check my answer, I just executed it with steps i mentioned in answer, and it worked as I expected and mentioned. So, If you could point out where I am going wrong that will be helpful. – Priyesh Feb 28 '14 at 09:45
  • ' Subclassing is a feature of....'. You then go on to demonstrate subclassing on python 2 – tacaswell Feb 28 '14 at 12:10
  • Yes. And I have also written a line "Now, the same functionality is extended to Python 2.0 classes, by inheriting "object" base class in each class definition. ". Subclassing is indeed a feature of 3.0. However, they provide a way to have it in 2.0. It is not enforced on it's own in 2.0. This is what I meant to say. – Priyesh Feb 28 '14 at 12:51
  • 4
    python as always had the ability to sub-class (OO makes no sense with out it). The new feature added to new-style classes in the function `__subclasses__` which returns a list of currently defined daughter classes. – tacaswell Feb 28 '14 at 18:33
  • You provided the apt words for my thoughts. This is what I intended to write, but I guess, it was not properly penned. Thanks a lot. :) – Priyesh Mar 04 '14 at 09:11