One of the historical oddities of Python is that there are two different kinds of classes, so-called "classic" or "old-style" classes, and "new-style" classes or types. To understand the reason, we have to go back to the dawn of time and very early Python.
Back in the early Python 1.x days, built-in types like
int
,
str
and
list
were completely separate from classes you created with the
class
keyword. Built-in types were written in C, classes were written in Python, and the two could not be combined. So in Python 1.5, you couldn't inherit from built-in types:
>>> class MyInt(int):
... pass
...
Traceback (innermost last):
File "", line 1, in ?
TypeError: base is not a class object
If you wanted to inherit behaviour from a built-in type, the only way to do so was by using
delegation, a powerful and useful technique that is unfortunately underused today. At the time though, it was the only way to solve the problem of subclassing from built-in types, leading to useful recipes like
this one from Alex Martelli.
But in Python 2.2,
classes were unified with built-in types. This involved a surprising number of changes to the behaviour of classes, so for backwards-compatibility, both the old and the new behaviour was kept. Rather than introduce a new keyword, Python 2.2 used a simple set of rules:
- If you define a class that doesn't inherit from anything, it is an old-style classic class.
- If your class inherits from another classic class, it too is a classic class.
- But if you inherit from a built-in type (e.g.
dict
or list
) then it is a new-style class and the new rules apply.
- Since Python supports multiple inheritance, you might inherit from both new-style and old-style classes; in that case, your class will be new-style.
To aid with this, a new built-in type was created,
object
.
object
is the parent type of all new-style classes and types, but not old-style classes. Curiously,
isinstance(classic_instance, object)
still returns True, even though
classic_instance
doesn't actually inherit from
object
. At least that is the case in Python 2.4 and above, I haven't tested 2.2 or 2.3.
There are a few technical differences in behaviour between the old- and new-style classes, including:
super
only works in new-style classes.
- Likewise for
classmethod
and staticmethod
.
- Properties appear to work in classic classes, but actually don't. They seem to work so long as you only read from them, but if you assign to a property, the setter method is not called and the property is replaced.
- In general, descriptors of any sort only work with new-style classes.
- New-style classes support
__slots__
as a memory optimization.
- The rules for resolving inheritance of old- and new-style classes are slightly different, with old-style classes' method resolution order being inconsistent under certain circumstances.
- New-style classes optimize operator overloading by skipping dunder methods like
__add__
which are defined on the instance rather than the class.
The complexity of having two kinds of class was always intended to be a temporary measure, and in Python 3, classic classes were finally removed for good. Now,
all classes inherit from
object
, even if you just write
class MyClass:
with no explicit bases.