While writing the article on the internals of Python callables, it occurred to me that some things in Python have more than one name. At the same time, some names are sometimes used to refer to more than one entity, and which one is implied has to be understood from context. Therefore, I think it's a good idea to collect this nomenclature in a single place for the sake of my future writings. This way I'll just be able to point here every time I discuss these topics, instead of explaining them over and over again.

Specifically, I want to define what I mean by types, objects, classes and instances. Note that this refers to Python 3.x, but is mostly applicable for 2.x as well [1].

Objects

It's easiest to start with objects. The Python data model reference has a pretty good definition:

Objects are Python’s abstraction for data. All data in a Python program is represented by objects or by relations between objects. (In a sense, and in conformance to Von Neumann’s model of a “stored program computer,” code is also represented by objects.)

Every object has an identity, a type and a value.

So, everything in Python is an object. Lists are objects. 42 is an object. Modules are objects. Functions are objects. Python bytecode is also kept in an object. All of these have types and unique IDs:

>>> def foo(): pass
...
>>> type(foo), id(foo)
(<class 'function'>, 38110760)
>>> type(foo.__code__), id(foo.__code__)
(<class 'code'>, 38111680)

This "everything is an object" model is backed by the CPython implementation. Indeed, if you look into the code of CPython, you'll notice that every entity mentioned above can be manipulated via a pointer to the PyObject base struct.

Types

The data model reference is useful here too:

[...] An object’s type determines the operations that the object supports (e.g., “does it have a length?”) and also defines the possible values for objects of that type.

So, every object in Python has a type. Its type can be discovered by calling the type builtin function [2]. The type is an object too, so it has a type of its own, which is called type. This last fact may not be very exciting or useful when you're just writing Python code, but it's hugely important if you want to understand the internals of CPython:

>>> type(42)
<class 'int'>
>>> type(type(42))
<class 'type'>
>>> type(type(type(42)))
<class 'type'>

Yep, it's turtles all the way down.

Classes

In the olden days, there was a difference between user-defined classes and built in types. But since 2.2, as long as you're using "new-style" classes (classes that inherit from object in 2.x, and are default in 3.x), there is no real difference. Essentially, a class is a mechanism Python gives us to create new user-defined types from Python code.

>>> class Joe: pass
...
>>> j = Joe()
>>> type(j)
<class '__main__.Joe'>

Using the class mechanism, we've created Joe - a user-defined type. j is an instance of the class Joe. In other words, it's an object and its type is Joe.

As any other type, Joe is an object itself, and it has a type too. This type is type:

>>> type(type(j))
<class 'type'>

The terms "class" and "type" are an example of two names referring to the same concept. To avoid this confusion, I will always try to say "type" when I mean a type, and "user-defined class" (or "user-defined type") when referring to a new type created using the class construct. Note that when we create new types using the C API of CPython, there's no "class" mentioned - we create a new "type", not a new "class".

Instances

Not unlike the ambiguity between "class" and "type", "instance" is synonymous to "object". Think of it this way: objects are instances of types. So, "42 is an instance of the type int" is equivalent to "42 is an int object". I usually use "instance" and "object" interchangeably. In some cases when I want to specifically refer to objects as artifacts of the CPython implementation, I will try to use "instance" to refer to actual instances of classes. Another place where the term "instance" is explicitly used by Python is in built-ins like isinstance and the special __instancecheck__ attribute.

Conclusion

As we've seen, there are two pairs of roughly synonymous terms in Python nomenclature. Types and classes are interchangeable concepts. I prefer to say "type" wherever possible, leaving the term "class" for user-defined types created with the "class" construct. IMHO "type" is a better term, and Python wouldn't be worse if the "class" concept was wiped out completely.

Similarly, objects and instances are terms that mean the same thing, but perhaps from slightly different angles. Sometimes it's more convenient to use "instance" (i.e. when specifically talking about specific objects being instances of specific types - as in "j is an instance of Joe"), and sometimes it's better to use "object" (i.e. when discussing the guts of the CPython implementation).

I sincerely hope this post is more helpful than confusing! For me, it's an aid that serves as a simple glossary when my usage of these terms in some article may be unclear or ambiguous.

[1]As long as you forget about the existence of classic 2.x classes and take it as a fact that all user-defined classes inherit from object.
[2]An alternative is the __class__ attribute.