What is the Python type() function?

The Python type() function is a basic Python function for working with types. As part of the Python implementation, it belongs to the core of the language.

What is the type() function in Python for?

The Python type() function is used in two different scenarios:

  1. To get the type of a Python object
  2. To dynamically create a new type

Let’s consider the first case which is much more useful in day-to-day use.

Get the type of an object with type()

Python is a dynamic language. This means that types are only determined at runtime and are bound to values instead of variables. From this circumstance arises the necessity to determine the type of an object at runtime.

Let’s call Python’s type() function and pass an object as the only parameter. In return we get the type of the object, e.g. int or str:

assert type(42) == int
# Type of `str(42)` is `str`
assert type(str(42)) == str

If we call the type() function in the Python REPL, the textual representation of the returned object will mention ‘class’ instead of ‘type’:

# Returns "<class 'int'>" inside REPL

What seems confusing at first makes perfect sense, because in Python, ‘everything is an object’. In Python, the object type corresponds to its class. Thus, calling the type() function is generally equivalent to reading the __class__ attribute:

# Should hold in most cases
assert type(obj) is obj.__class__

Create a new type with type()

Now, let’s explore the second possible use of the type() function. When called with three arguments, the function enables us to dynamically create a new type:

type(name, bases, dict, **kwds)

In this form, the Python type() function behaves similarly to the class keyword. The code type = type("Type", bases, dict) can be thought of as an equivalent class definition:

class <Type>(<bases>):

Below is an example of using Python type() to create new types. Here’s an overview of the arguments:

name bases dict **kwds
Name of the new type as string Tuple with base classes Dict with attributes of the new class Additional arguments for metaclass instantiation

With Deploy Now from IONOS you can deploy websites and apps easily using GitHub.

How does Python type() work?

When using the type() function to determine the type of an object, the return value isn’t a string, but an independent object:

# Value returned by `type(42)` is not a string
assert type(42) != 'int'
# We get back an object named `int`
assert type(42) == int

Let’s look at a few examples of return values of the type() function for objects of different types:

# Python objects of different types
different_objs = None, True, 42, 'John', ('Walter', 'White'), ...
# Print out the type of each object
for obj in different_objs:
  print(f"{obj}: {type(obj)}")
type() call Textual representation
type(None) <class 'NoneType'>
type(True) <class 'bool'>
type(42) <class 'int'>
type('John') <class 'str'>
type(('Walter', 'White')) <class 'tuple'>
type(...) <class 'ellipsis'>

The question arises: what’s the type of the object returned by type()? Let’s try it out. We call the Python type() function and pass the return value of another type() call:

# Returns: "<class 'type'>"

It shows that in addition to Python’s built-in type() function, there’s the type type of the same name. This type represents all other Python types, as illustrated through an example:

# DifferentPython objects
different_objs = None, True, 42, 'John', ('Walter', 'White'), ...
# Check the type of each object's type
for obj in different_objs:
  # Show that the type’s type is always `type`
  assert type(type(obj)) is type

So the type of any Python type is type. If that sounds confusing, it gets even better: the type of the type object is another type. This can be continued forever, like a snake biting its own tail:

# It's `type` all the way down
assert type(type(type(type))) is type

To clear up any confusion, it’s essential to delve deeper into Python’s object-oriented programming (OOP) system. Python’s built-in type object represents a so-called metaclass. A metaclass behaves to a class as a class behaves to an object. In other words, a metaclass is a template for a class, while a class is a template for an object:

Template Instance
Class Object
metaclass class
example: type int, str etc.
example:int 42
example: str “Walter White”

How to use the type() function in Python?

Python’s type() function is commonly used to retrieve the type of an object during runtime. This functionality is valuable due to Python being a dynamically typed language. In contrast, statically typed languages like Java require variable types to be declared and cannot be altered during runtime.

// Declare variable as `boolean`
boolean answer;
// Attempting to assign `int` value
// Throws type error
answer = 42;

In contrast, variables in Python are simply names that refer to typed values. At any time during code execution, a name can be referenced to a value with a different type. So to determine the type of a Python variable at runtime, we need the type() function:

# Assign Boolean value
answer = True
# Show that type is `bool`
assert type(answer) is bool
# Reassign integer value
answer = 42
# Show that type is now `int`
assert type(answer) is int

Checking the type of function arguments in Python

When defining a function, it’s often necessary to check the arguments for compliance with certain criteria. This includes checking if the arguments fall within certain limits or confirming that they are of suitable types. By performing these checks, potential runtime errors can be avoided.

Let’s illustrate the use of the type() function with an example. We’ll define a function that adds up a list of numbers. For this to work, we need to ensure that each argument is a number. We use type() inside an assert statement:

# Function to add up numeric arguments
def add_numbers(*args):
  result = 0
  # Check each argument
  for arg in args:
    # Abort with error message if argument is not an `int` or `float`
    assert type(arg) in (int, float), f"Argument `{arg}` is not a number"
    # Add argument's value to total
    result += arg
  return result

# Show that it works for numbers
assert add_numbers(35, 7) == 42
# The following will fail
add_numbers(29, 'thirteen')

Debugging in Python REPL with the type() function

An advantage of using an interpreted language like Python is the interactive execution of code in the REPL (Read-Eval-Print-Loop). The approach allows fast prototyping and debugging via inspection of objects in memory.

Let’s imagine the following scenario. Our code contains a variable answer that is supposed to contain a Boolean value. We find that the type doesn’t match our expectations and use Python’s type() function to output the type. As it turns out, we accidentally wrote the Boolean value in quotes – a common mistake, especially among beginners:

# Accidentally set to string
answer = 'False'
# Assertion will fail
assert type(answer) is bool
# Correct to Boolean value
answer = False
# Now assertion holds
assert type(answer) is bool

Create Python classes dynamically using the type() function

As shown, Python classes can be created dynamically, i.e. during runtime, using the type() function. This is useful for families of classes, among other things. Let’s demonstrate the concept of class families with an example using HTML tags. First, we create a base class tag where objects of this class can represent themselves as HTML code.

# Class representing HTML tag
class Tag:
  # Initialize HTML tag with contents
  def __init__(self, *args):
    # Join contents of tag
    self.content = "".join([arg.__str__() for arg in args])
  # String representation returns HTML
  def __str__(self):
    return f"<{self.name}>{self.content}</{self.name}>"

To **specialise the base class tag via inheritance for specific HTML tags like <p> or <h1>we can utilise the type() function again. Let’s illustrate this with an example:

# Create `P` class
P = type('P', (Tag,), {"name": 'p'})
  1. Name of the new class as string.

  2. Tuple with base classes.

    Python allows multiple inheritance; to derive from only one class, we use the notation (ClassName,).

  3. Dict with the name of the class and additional entries if necessary.

    The entries can also be functions.

Subsequently, we instantiate a p tag and check that the representation works correctly:

# Instantiate `p` tag
greeting = P("Hello world")
assert str(greeting) == '<p>Hello world</p>'

The same effect can be achieved by analogous class definition:

# Create `P` class
class P(Tag):
  name = 'p'

As another example, we create classes for headings with type(). Using the dynamic class creation capability of type(), we can create classes for all six heading levels at once using list comprehension:

h_1_to_6 = ( f"h{n}" for n in range(1, 7) )
headings = [type(heading, (Tag,), {"name": heading}) for heading in h_1_to_6]

As shown, it’s worth using the type() function to create multiple related subclasses. We demonstrate the approach using the more complex example of defining classes for modelling playing cards. First, we define a superclass Card using the class keyword:

# Class representing abstract playing card
class Card:
  def __init__(self, number):
    self.number = number
  # String representation
  def __str__(self):
    return f"{self.number} of {self.suite}"

Next, we create subclasses for the four map colours using type():

# Create concrete types for each suite
Clubs = type('Clubs', (Card,), {'suite': 'Clubs'})
Diamonds = type('Diamonds', (Card,), {'suite': 'Diamonds'})
Hearts = type('Hearts', (Card,), {'suite': 'Hearts'})
Spades = type('Spades', (Card,), {'suite': 'Spades'})

Now the individual cards can be instantiated:

# Instantiate a 7 of Spades
card = Spades(7)
# Show that it worked
assert str(card) == '7 of Spades'

What are the limits of the type() function?

Python’s type() function is useful. However, there are some cases where the function reaches its limits. Fortunately, Python has some workarounds. Let’s look at some of them.

Break down inheritance hierarchies with isinstance()

type() only determines the actual type of a Python object, but ignores the inheritance hierarchy. Let’s illustrate this dilemma with our playing card example from the last section. The type of a 7 of spades should be both ‘playing card’ and ‘spade’. However, with type() this cannot be determined:

# Create a Seven of Spades
card = Spades(7)
# Our card is a Spade alright
assert type(card) is Spades
# But not a card??
assert type(card) is not Card

To correctly break down the underlying polymorphism, we use the isinstance() function.

# Seven of Spades is a `Spade`
assert isinstance(card, Spades)
# And is also a `Card`
assert isinstance(card, Card)

Simplify Python object type detection with match-case

As shown above, the type() function is often used to determine the type of an object at runtime. To distinguish several possible types from one another, an if-elif-else construct is used if necessary:

# Determine type of object
if type(obj) is int:
elif type(obj) is float:
elif type(obj) is ...:
  print("Something else")

As of version 3.10, however, Python knows the match-case statement. This recognises types without calling the type() function.

In a case block, constructor functions like int(obj) or str(obj) can be used to match the block if the object has the respective type.

# Example object
obj = 42
# Determine object type
match obj:
  case int(obj):
    print(f"{obj} is `int`")
  case float(obj):
    print(f"{obj} is `float`")
  case _:
    print(f"{obj} is something else")

To get started with Python, check out our Python tutorial and our overview of useful Python operators.

In order to provide you with the best online experience this website uses cookies. By using our website, you agree to our use of cookies. More Info.
Manage cookies