tags:

views:

134

answers:

1

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.

+1  A: 
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.

"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__']
manifest
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
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