Python: la función type()

La función type() es una función básica de Python para trabajar con tipos. Como parte de la implementación de Python, pertenece al núcleo del lenguaje.

¿Para qué sirve la función type() en Python?

La función type() se utiliza en Python con dos objetivos bastante diferentes:

  1. Determinar el tipo de un objeto
  2. Crear dinámicamente un nuevo tipo

Veamos primero el primer caso, que es mucho más útil en el uso cotidiano.

Determinar el tipo de un objeto con type()

Python es un leguaje de tipado dinámico. Esto significa que los tipos se determinan en tiempo de ejecución y están ligados a valores en lugar de a variables. Debido a esta característica, es necesario determinar el tipo de un objeto en tiempo de ejecución.

Llamamos a la función type() de Python y le pasamos un objeto como único parámetro. Como resultado obtenemos el tipo del objeto, por ejemplo into str:


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

Si llamamos a la función type() en el REPL de Python, la representación textual contiene la palabra “class” en lugar de “type”:

# Returns "<class 'int'>" inside REPL
type(42)
Python

Aunque al principio puede parecer confuso, tiene sentido. Python sigue el principio de “todo es un objeto”. En Python, el tipo de un objeto corresponde a su clase. Por lo tanto, llamar a la función type() es equivalente a acceder al atributo __class__.

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

Crear un nuevo tipo con type()

Veamos ahora el segundo uso posible de la función type(). Si se llama con tres argumentos, la función nos permite crear dinámicamente un nuevo tipo:

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

En esta forma, la función type() de Python funciona de forma análoga a la palabra clave class. El código Type = type(“Type”, bases, dict) equivale aproximadamente a la siguiente definición de clase:

class <Type>(<bases>):
    <dict>
Python

A continuación, te mostramos algunos ejemplos concretos del uso de la función type() de Python para crear nuevos tipos. Antes, sin embargo, te presentamos una descripción general de los argumentos:

name bases dict **kwds
Nombre del nuevo tipo como cadena de texto Tupla con clases de base Diccionario con los atributos de la nueva clase Otros argumentos para la instalación de la metaclase
Consejo

Con Deploy Now de IONOS puedes implementar tu página web o aplicación a través de GitHub.

¿Cómo funciona la función type() de Python?

Cuando se utiliza la función type() para determinar el tipo de un objeto, el valor de retorno no es una cadena, sino un objeto independiente:

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

Veamos algunos ejemplos de valores de retorno de la función type() para objetos de tipos completamente diferentes:

# 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)}")
Python
Llamada a type() Representación textual
type(None) <class 'NoneType'>
type(True) <class 'bool'>
type(42) <class 'int'>
type('John') <class 'str'>
type(('Walter', 'White')) <class 'tuple'>
type(...) <class 'ellipsis'>

Es posible que te preguntes cuál es el tipo del objeto devuelto por type(). Hagamos la prueba. Llamamos a la función type() de Python y le pasamos el valor de retorno de otra llamada a type():

# Returns: "<class 'type'>"
type(type(42))
Python

Vemos que, además de la función type() incorporada en Python, existe el tipo type con el mismo nombre. Este es el tipo de todos los demás tipos en Python, como mostramos en este ejemplo:

# 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
Python

El tipo de cada tipo en Python es, de hecho, type. Puede sonar confuso, y aún hay más: el tipo del objeto type es también type. Esto puede continuar indefinidamente:

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

Para aclarar la confusión, se necesita una comprensión más profunda del sistema de programación orientada a objetos de Python. El objeto incorporado type de Python representa una metaclase. Una metaclase se comporta con una clase como una clase se comporta con un objeto. En otras palabras, una metaclase es una plantilla para una clase, mientras que una clase es una plantilla para un objeto:

Plantilla Instancia
Clase Objeto
Metaclase Clase
Ejemplo: type int, str etc.
Ejemplo:int 42
Ejemplo: str “Walter White”

¿Cómo se utiliza la función type() en Python?

Normalmente, la función type() de Python se utiliza para obtener el tipo de un objeto en tiempo de ejecución. Esto es útil porque Python es un lenguaje de tipado dinámico. En un lenguaje de tipado estático como Java, un tipo está ligado a una variable por declaración y no puede ser cambiado en tiempo de ejecución:

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

Por el contrario, las variables en Python son simplemente nombres que hacen referencia a valores tipados. En cualquier momento durante la ejecución del código, un nombre puede referirse a un valor con un tipo diferente. Para determinar el tipo de una variable Python en tiempo de ejecución, necesitamos la función type():

# 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
Python

Comprobación del tipo de argumentos de una función en Python

Al definir una función, a menudo es necesario comprobar que los argumentos cumplen determinados criterios. Por ejemplo, un argumento solo puede encontrarse dentro de ciertos límites o solo se admiten argumentos de tipos adecuados. Así se evitan errores en tiempo de ejecución.

Veamos un ejemplo de uso de la función type(). Definimos una función que suma una lista de números. Para que funcione, necesitamos asegurarnos de que cada argumento es realmente un número. Utilizaremos type() dentro de una sentencia assert:

# 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')
Python

Depuración en Python REPL con la función type()

Una de las ventajas de utilizar un lenguaje interpretado como Python es la ejecución interactiva de código en el REPL (Read Eval Print Loop). Este enfoque permite la creación rápida de prototipos y la depuración directa mediante la inspección de los objetos en memoria.

Imaginemos el siguiente escenario: nuestro código contiene una variable answer que se supone que contiene un valor booleano. Descubrimos que el tipo no coincide con lo que esperábamos y utilizamos la función type() de Python para obtener el tipo real. Resulta que accidentalmente escribimos el valor booleano entre comillas. Es un error común, especialmente entre principiantes:

# 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
Python

Creación dinámica de clases Python con la función type()

Como hemos visto, las clases Python pueden crearse dinámicamente, es decir, en tiempo de ejecución, con la función type(). Esto es útil, entre otras cosas, para las familias de clases, que mostramos con el ejemplo de las etiquetas HTML. En primer lugar, creamos una clase base tag, cuyos objetos pueden representarse a sí mismos como código HTML:

# 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}>"
Python

A continuación, especializaremos la clase base mediante herencia para los tags específicos como <p> o <h1>. Para ello, llamamos a la función type() con tres argumentos:

# Create `P` class
P = type('P', (Tag,), {"name": 'p'})
Python
  1. Nombre de la nueva clase en forma de cadena.

  2. Tupla con las clases base.

    Python permite la herencia múltiple; para derivar de una sola clase, utilizamos la notación (ClassName,).

  3. Dict con el nombre de la clase y opcionalmente otros elementos.

    Los elementos pueden ser funciones.

A continuación, instanciamos una etiqueta p y comprobamos que la representación funciona correctamente:

# Instantiate `p` tag
greeting = P("Hello world")
assert str(greeting) == '&lt;p&gt;Hello world&lt;/p&gt;'
Python

El mismo efecto puede conseguirse mediante la definición de clases análogas:

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

Como otro ejemplo, creamos clases para encabezados utilizando type(). Dado que la creación de las clases es dinámica, podemos generar las clases para los seis niveles de encabezado de una vez utilizando una 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]
Python

Como hemos demostrado, vale la pena utilizar la función type() para crear cómodamente múltiples subclases relacionadas. Mostraremos este enfoque con un ejemplo más complejo: definiendo clases para modelar cartas de naipes. Primero, definiremos una superclase Card utilizando la palabra clave class:

# 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}"
Python

A continuación, creamos subclases para los cuatro palos de cartas utilizando 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'})
Python

Ahora podemos instanciar cada carta individual sin problemas:

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

¿Qué límites tiene la función type()?

La función type() de Python es útil. Sin embargo, hay algunos usos en los que la función alcanza sus límites para resolverlos. Afortunadamente, Python ofrece enfoques adecuados para abordarlos. Veamos algunos de ellos.

Descomponer jerarquías de herencia con isinstance()

type() solo determina el tipo real de un objeto Python, pero ignora la jerarquía de herencia. Representamos el dilema resultante con nuestro ejemplo de naipes de la última sección. El tipo de un 7 de picas debería ser tanto “naipe” como “pica”. Sin embargo, esto no se puede determinar con type():

# 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
Python

Para descomponer correctamente el polimorfismo subyacente, hacemos uso de la función isinstance().

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

Simplificar la detección de tipos de objetos en Python con match-case

Como hemos visto anteriormente, la función type() se utiliza a menudo para determinar el tipo de un objeto en tiempo de ejecución. Para distinguir varios tipos posibles entre sí, se puede utilizar una construcción if-elif-else:

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

Desde la versión 3.10, sin embargo, Python introdujo la sentencia match-case. Esta permite, entre otras cosas, reconocer tipos sin tener que llamar a la función type().

Dentro de un bloque case se pueden utilizar funciones constructoras como int(obj) o str(obj). El bloque coincide si el objeto tiene el tipo correspondiente:

# 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")
Python
Consejo

Para iniciarte en el lenguaje, utiliza nuestro tutorial de Python y nuestro artículo sobre operadores de Python.