In CPython, types implemented in C actually are part of the type tree

December 24, 2020

In Python, in theory all types descend from object (they are direct or indirect subclasses of it). For years, I've believed (and written) that this was not the case at the implementation level for types written in native C code in CPython (the standard implementation of Python and the one you're probably using). Types written in C might behave as if they descended from object, but I thought their behavior was actually entirely stand-alone, implemented by each type separately in C. Courtesy of Python behind the scenes #6: how Python object system works, I've discovered that I'm wrong.

In CPython, C level Python types are not literally subclasses of the C level version of object, because of course C doesn't have classes and subclasses in that sense. Instead, you usually describe your type by defining a PyTypeObject struct for it, with all sorts of fields that you fill in or don't fill in as you need them, including a tp_base field for your base type (if you want more than one base type, you need to take the alternate path of a heap type). When CPython needs to execute special methods or other operations on your type, it will directly use fields on your PyTypeObject structure (and as far as I know, it only uses those fields, with no fallbacks). On the surface, this looks like the tp_base field is essentially decorative and is only used to report your claimed __base__ if people ask.

However, there is a bit of CPython magic hiding behind the scenes. In order to actually use a PyTypeObject as a type, you must register it and make it ready by calling PyType_Ready. As part of this, PyType_Ready will use your type's tp_base to fill in various fields of your PyTypeObject if you didn't already do that, which effectively means that your C level type will inherit those fields from its base type (and so on all the way up to object). This is outlined in a section of the C API, but of course I never read the C API myself because I never needed to use it. The how [the] Python object system works article has more details on how this works, if you're curious, along with details on how special methods also work (which is more interesting than I had any idea, and I've looked at this area before).

(The distinction between what is considered a 'type' and what is considered a 'class' by repr() is somewhat arbitrary; see the sidebar here. C level things defined with PyTypeObject will probably always be considered types instead of classes.)


Comments on this page:

By Peter Donis at 2020-12-24 22:23:17:

Note that the repr() display quirk you describe is only present in Python 2. In Python 3, repr() calls all of these things a "class".

By cks at 2020-12-25 01:30:12:

You're entirely right about the repr() results in Python 3. I just assumed that Python 3 behaved the same as 2 when I wrote this entry, without checking. I found the whole change interesting enough to write an entry about it, as parts of the background go back to Python 1 and the early days of Python 2.

Written on 24 December 2020.
« Using constant Python hash functions for fun and no real profit
In Python 3, types are classes (as far as repr() is concerned) »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Thu Dec 24 00:05:53 2020
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.