Cuando Python dice que “todo es un objeto”, no está usando una metáfora ni exagerando para sonar elegante. Es una afirmación técnica y literal: el número 42, la cadena "hola", la función print, e incluso la clase int misma son objetos que viven en memoria, tienen una identidad, un tipo, y cargan consigo tanto datos como comportamiento.
En la mayoría de los lenguajes, los tipos primitivos como enteros o booleanos son valores “planos”, sin estructura. Python no hace esa distinción. Aquí, 42 es una instancia de la clase int, igual que un objeto que tú mismo crearías con class. Eso puede sonar extraño al principio, pero verás que es la decisión de diseño que hace que Python sea tan coherente y expresivo.
La evidencia más directa es type(). Cuando escribes type(42) en el intérprete, obtienes <class 'int'>. No “número”, no “primitivo”: una clase concreta. Igual con type("hola") → <class 'str'>, y type(print) → <class 'builtin_function_or_method'>. Todo tiene clase. Todo tiene tipo. Todo es un objeto.
¿Por qué funciona así? Porque Python fue diseñado con un modelo de objetos unificado: en lugar de tener reglas distintas para primitivos, funciones y clases, hay una sola regla. Todo objeto tiene tres cosas garantizadas: una identidad (su dirección en memoria, visible con id()), un tipo (su clase, visible con type()), y un valor (los datos que contiene). A partir de ahí, cada tipo añade sus propios atributos (datos asociados) y métodos (comportamiento), accesibles ambos con la notación de punto (.).
¿Cuándo importa saber esto? Desde el primer día. Entender que "hola" es un objeto explica por qué puedes escribir "hola".upper() sin importar nada, por qué puedes pasar una función como argumento a otra función, y por qué type() e isinstance() funcionan igual sobre cualquier cosa. También es la base del duck typing: si el objeto que tienes tiene el método que necesitas, funciona, sin importar su tipo exacto.
Lo que rompe si lo ignoras: puedes escribir Python sin saber esto, pero cometerás errores conceptuales costosos. Por ejemplo, intentar copiar una lista con b = a y confundirte cuando ambas “se modifican solas”, porque no entendiste que a y b son dos nombres que apuntan al mismo objeto. O sorprenderte de que las funciones puedan guardarse en variables o meterse en listas, cuando en realidad eso es trivial: son objetos como cualquier otro.
# Evidencia directa: todo tiene tipo y comportamiento
# --- Números ---
n = 42
print(type(n)) # <class 'int'>
print(n.bit_length()) # 6 → 42 necesita 6 bits para representarse
# --- Cadenas ---
greeting = "hola mundo"
print(type(greeting)) # <class 'str'>
print(greeting.upper()) # HOLA MUNDO
print(greeting.split()) # ['hola', 'mundo']
# --- Funciones ---
print(type(print)) # <class 'builtin_function_or_method'>
def double(x):
return x * 2
print(type(double)) # <class 'function'>
# Las funciones son objetos: puedes asignarlas, guardarlas, pasarlas
operations = [double, abs, str]
for op in operations:
print(op(-5)) # -10, 5, '-5'
# --- Clases también son objetos ---
print(type(int)) # <class 'type'> → hasta 'int' tiene tipo
# --- id() revela la identidad: la dirección en memoria del objeto ---
a = "python"
b = "python"
print(id(a), id(b)) # pueden ser iguales (interning) o distintos, pero ambos tienen id
# --- Duck typing en acción ---
# No preguntamos "¿es esto una lista?", preguntamos "¿tiene .append()?"
def add_item(collection, item):
collection.append(item) # funciona con cualquier objeto que tenga .append
return collection
import collections
my_list = [1, 2]
my_deque = collections.deque([1, 2])
print(add_item(my_list, 3)) # [1, 2, 3]
print(add_item(my_deque, 3)) # deque([1, 2, 3])
Fíjate en lo que está pasando en cada bloque. Cuando llamas n.bit_length() sobre el entero 42, estás usando la notación de punto exactamente igual que si n fuera una instancia de una clase que tú escribiste. No hay magia especial para los enteros: int es una clase, 42 es su instancia, y bit_length es uno de sus métodos.
Con greeting.upper() y greeting.split() ocurre lo mismo: str es una clase llena de métodos. La notación de punto es la interfaz universal para acceder al comportamiento de cualquier objeto, sin importar si lo creó Python internamente o tú en tu propio código.
El bloque de operations muestra algo que en otros lenguajes requeriría constructos especiales (punteros a función, lambdas, interfaces): aquí simplemente metiste tres funciones en una lista porque son objetos. El bucle las llama una por una con op(-5). No hay nada especial que aprender: ya sabías que puedes iterar listas y llamar funciones. El modelo uniforme hace que se combinen sin fricción.
type(int) devolviendo <class 'type'> es el detalle que más descoloca al principio. Significa que incluso las clases son objetos, instancias de una metaclase llamada type. No necesitas entender las metaclases ahora, pero sí registrar el patrón: el modelo no tiene excepciones.
El ejemplo de duck typing en add_item ilustra por qué el modelo uniforme simplifica el código real. La función no hace isinstance(collection, list). Asume que si el objeto tiene .append(), puede usarlo. Una list lo tiene. Un deque lo tiene. Ambos funcionan. Eso es duck typing: en Python no preguntas qué es un objeto, preguntas qué puede hacer.
Errores que debes conocer
Error: Confundir “asignar una variable” con “copiar un objeto”. Cuando escribes b = a, Python no crea una copia: crea un segundo nombre que apunta al mismo objeto. Con tipos mutables como listas, esto produce efectos sorprendentes.
# ❌ Wrong a = [1, 2, 3] b = a # b y a apuntan al MISMO objeto b.append(4) print(a) # [1, 2, 3, 4] ← sorpresa # ✅ Right a = [1, 2, 3] b = a.copy() # ahora b es un objeto distinto b.append(4) print(a) # [1, 2, 3] ← sin sorpresas
a.copy() crea un nuevo objeto lista con los mismos valores. A partir de ahí, a y b son independientes.
Error: Llamar type() para comparar tipos en lugar de usar isinstance(). type(x) == int falla si x es instancia de una subclase de int, porque el modelo de objetos de Python incluye herencia.
# ❌ Wrong
class MyInt(int):
pass
n = MyInt(5)
print(type(n) == int) # False ← aunque n "es" un int
# ✅ Right
print(isinstance(n, int)) # True ← respeta la jerarquía de clases
isinstance() sube por la cadena de herencia, que es exactamente lo que quieres cuando trabajas con el modelo de objetos de Python.
N° 18