Skip to main content
In Python, type is a built-in metaclass and function that serves a dual purpose: it returns the exact type of an existing object when invoked with a single positional argument, and it dynamically constructs a new class object when invoked with exactly three positional arguments (alongside optional keyword arguments). It is the root metaclass in Python’s object model, meaning all classes—including built-ins, user-defined classes, and type itself—are instances of type.

Single-Argument Syntax: Type Inspection

When passed exactly one argument, type() returns the class object that instantiated the argument.
  • object: Any Python object.
  • Return Value: The class object of the argument.
Unlike accessing the __class__ attribute, type() always reads the underlying C-level type pointer directly (such as ob_type in CPython) to determine the true type. Consequently, type() bypasses any Python-level interception of __class__. This includes custom descriptors (e.g., @property), overriding __getattribute__, or shadowing the attribute with a regular class variable. However, if __class__ is dynamically reassigned on an instance (e.g., x.__class__ = NewClass), Python updates the underlying ob_type pointer at the C level. In this specific scenario, type(x) will accurately reflect the newly assigned class because the internal pointer itself was modified.

Dynamic Class Creation

When passed exactly three positional arguments, type() acts as a class constructor (metaclass), allocating memory and initializing a new class object at runtime. Passing two, or four or more positional arguments raises a TypeError. This three-argument form is the underlying mechanism Python uses when it parses a class statement.
  • name (str): The name of the class. Becomes the __name__ attribute.
  • bases (tuple): A tuple of parent classes for inheritance. Becomes the __bases__ attribute.
  • dict (dict): A dictionary containing the namespace (attributes and methods) for the class body. This dictionary is used to populate the class namespace. The resulting class’s __dict__ attribute is a distinct, read-only mappingproxy object, not a reference to the original dictionary passed to the constructor.
  • **kwds: Optional keyword arguments that are passed to the __init_subclass__ method of the base classes or to custom metaclasses.

The Metaclass Hierarchy

In Python’s type system, there is a strict separation between the inheritance hierarchy and the instantiation hierarchy.
  • object is the root of the inheritance hierarchy. All classes inherit from object.
  • type is the root of the instantiation hierarchy. All classes are instances of type.
Because type is itself a class, it is an instance of itself, and because it is a class, it inherits from object.
When a custom metaclass is defined, it must inherit from type to properly hook into Python’s class creation mechanics.
Tired of Poor Python Skills? Fix That With Deep Grasping!Learn More