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.
New-style classes were introduced in Python 2.2 to unify the concepts of class and type. A new-style class is simply a user-defined type, no more, no less. If x is an instance of a new-style class, then type(x) is typically the same as x.
In the base class object , the __new__ method is defined as a static method which requires to pass a parameter cls . cls represents the class that is needed to be instantiated, and the compiler automatically provides this parameter at the time of instantiation.
The class from which a class inherits is called the parent or superclass. A class which inherits from a superclass is called a subclass, also called heir class or child class. Superclasses are sometimes called ancestors as well. There exists a hierarchical relationship between classes.
All the Python built-ins are subclasses of object and I come across many user-defined classes which are too.
The __module__ property is intended for retrieving the module where the function was defined, either to read the source code or sometimes to re-import it in a script.
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__']
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With