Apr. 23rd, 2014

import_that: XKCD guy flying with Python (Default)
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.

Profile

import_that: XKCD guy flying with Python (Default)
Steven D'Aprano

May 2015

S M T W T F S
     12
345678 9
10111213141516
17181920212223
24252627282930
31      

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags