The single-argument form, type(obj), is the everyday use: it returns the exact class an object belongs to, e.g. type(5) is int. Every object in Python has a type, including classes themselves. The rarely-used three-argument form dynamically builds a new class at runtime — it's what's happening behind the scenes whenever you write a class statement, since a plain class definition is roughly sugar for calling type() directly.
1Understanding type()
The single-argument form, type(obj), is the everyday use: it returns the exact class an object belongs to, e.g. type(5) is int. Every object in Python has a type, including classes themselves. The rarely-used three-argument form dynamically builds a new class at runtime — it's what's happening behind the scenes whenever you write a class statement, since a plain class definition is roughly sugar for calling type() directly.
Prefer isinstance() over comparing type(x) to a class directly — isinstance() also matches subclasses, which is almost always what you actually want.
print(type(42))
print(type("hello"))
print(type([1, 2, 3]))2Practical Example
Here is a real-world application of type() showing how it is used in production Python code.
# Dynamically creating a class, equivalent to "class Point: pass"
Point = type("Point", (), {"x": 0, "y": 0})
p = Point()
print(p.x, p.y)3Best Practices
Follow these guidelines when working with type():
1. Use isinstance() for type checks in conditionals; reserve type() for introspection/debugging
2. Use type(obj).__name__ to get a readable class name as a string
3. Avoid the 3-argument dynamic class creation unless you're writing a metaprogramming library
Tip: Prefer isinstance() over comparing type(x) to a class directly — isinstance() also matches subclasses, which is almost always what you actually want.
print(type(42))
print(type("hello"))
print(type([1, 2, 3]))