Skip to content

type() Function

The type() function returns the type of an object or creates a new type (class) dynamically.

Complexity Reference

Operation Time Space Notes
type(obj) O(1) O(1) Get object type
type(name, bases, dict) O(n) O(n) Create class, n = dict size

Getting Object Type

Basic Type Checking - Time: O(1)

# Get type of object - O(1)
print(type(42))           # <class 'int'>
print(type("hello"))      # <class 'str'>
print(type([1, 2, 3]))    # <class 'list'>
print(type({'a': 1}))     # <class 'dict'>
print(type(True))         # <class 'bool'>

Comparing Types

value = 42

# Check type - O(1)
if type(value) == int:
    print("Is integer")

if type(value) is int:  # Preferred
    print("Is integer")

# Use isinstance() for subclass checking - O(1)
if isinstance(value, (int, float)):
    print("Is number")

Type of Classes

class MyClass:
    pass

obj = MyClass()

# Type of instance - O(1)
print(type(obj))  # <class '__main__.MyClass'>

# Type of class - O(1)
print(type(MyClass))  # <class 'type'>

# Get class from instance - O(1)
cls = type(obj)
print(cls.__name__)  # 'MyClass'

Creating Classes Dynamically

Type Constructor - Time: O(n) where n = attributes

# Create class dynamically - O(n)
# type(name, bases, dict)

# Equivalent to:
# class MyClass:
#     x = 10
#     def method(self): return self.x

MyClass = type('MyClass', (), {
    'x': 10,
    'method': lambda self: self.x
})

obj = MyClass()
print(obj.x)        # 10
print(obj.method()) # 10

Dynamic Class with Methods

# Create class with methods - O(n)
def __init__(self, name):
    self.name = name

def greet(self):
    return f"Hello, {self.name}"

Person = type('Person', (), {
    '__init__': __init__,
    'greet': greet
})

p = Person("Alice")
print(p.greet())  # Hello, Alice

Class with Inheritance

# Create class with base - O(n)
class Base:
    def base_method(self):
        return "from base"

Derived = type('Derived', (Base,), {
    'derived_method': lambda self: "from derived"
})

obj = Derived()
print(obj.base_method())     # from base
print(obj.derived_method())  # from derived

type() vs isinstance()

# type() - exact type match - O(1)
if type(value) is int:
    print("Exact integer")

# isinstance() - checks subclass too - O(1)
if isinstance(value, int):
    print("Integer or subclass")

# isinstance() preferred for most cases
class MyInt(int):
    pass

val = MyInt(5)

print(type(val) is int)       # False
print(isinstance(val, int))   # True (preferred)

Metaclasses

Using type as Metaclass

# type is the metaclass of all classes
class MyMeta(type):
    def __new__(mcs, name, bases, namespace):
        print(f"Creating class {name}")
        return super().__new__(mcs, name, bases, namespace)

# Create class with metaclass - O(n)
MyClass = MyMeta('MyClass', (), {})
# Output: Creating class MyClass

Best Practices

# ✅ DO: Use isinstance() for type checking
if isinstance(value, (int, float)):
    print("Is number")

# ✅ DO: Use type() for exact type match when needed
if type(value) is int:
    print("Exactly int, not subclass")

# ✅ DO: Use __class__ for more specific type
print(obj.__class__.__name__)

# ❌ DON'T: Use type() for isinstance() purposes
if type(value) == int:
    print("Doesn't check subclasses")

# ❌ DON'T: Compare types with ==, use 'is'
if type(value) == int:  # Works but less preferred
    pass
if type(value) is int:  # Preferred
    pass

Further Reading