Declaración de variables en Python
Python permite escribir programas de forma muy libre: puedes declarar variables sin tipos, cambiar sus valores o incluso su tipo en cualquier momento. Esta flexibilidad hace que el lenguaje sea ideal para tareas exploratorias, prototipado y enseñanza inicial. Sin embargo, cuando el objetivo es construir bibliotecas reutilizables y mantenibles, esa misma libertad plantea nuevos desafíos.
En esta lección aprenderás cómo se declaran y manipulan variables en Python, y cómo implementar propiedades con lógica de acceso mediante decoradores. También analizaremos en qué se diferencia este modelo del enfoque de Kotlin —más estructurado y expresivo— y qué herramientas del ecosistema pueden ayudarte a recuperar parte de esa expresividad en tus diseños.
Al finalizar, contarás con una base sólida para decidir cuándo y cómo usar las herramientas de Python de forma responsable, entendiendo los beneficios de su flexibilidad y los riesgos de su falta de restricciones.
🐍 Variables en Python
A diferencia de Kotlin, Python no exige declarar el tipo de una variable ni usar palabras clave como val
o var
.
Simplemente se asigna un valor a un nombre, y el tipo se deduce automáticamente en tiempo de ejecución.
name = "Emilia"
mana = 80
Explicación
- Las variables se crean en el momento en que se les asigna un valor.
- El tipo de cada variable se infiere dinámicamente (en este caso,
str
paraname
eint
paramana
). - No existe una distinción entre referencias mutables e inmutables como
val
yvar
en Kotlin. - El concepto de inmutabilidad depende del tipo de objeto (por ejemplo,
int
ystr
son inmutables;list
ydict
son mutables).
Esta flexibilidad hace que Python sea más sencillo para principiantes, pero también puede esconder errores que en Kotlin serían detectados en tiempo de compilación.
🔄 Reasignación libre (mutabilidad de referencia)
En Python, puedes reasignar una variable en cualquier momento, sin importar el tipo de dato:
mana = 100
mana = 75 # ✅ Reasignación válida
Esto contrasta con Kotlin, donde puedes declarar una variable como inmutable usando val
, lo que impide cambiar su referencia.
Tipos inmutables y mutables
Aunque Python permite reasignar cualquier variable, no todos los objetos son mutables.
Tipos como int
, float
, str
o tuple
son inmutables: no se pueden modificar en el lugar, solo reemplazar.
En cambio, estructuras como list
, dict
o set
sí son mutables, y pueden modificarse directamente.
numbers = [1, 2, 3] # lista mutable
numbers.append(4) # ✅ modificación en el lugar
name = "Emilia"
name[0] = "A" # 🔥 Error: los strings son inmutables
🚫 Inmutabilidad por convención
Python no ofrece una forma nativa de declarar variables inmutables como val
en Kotlin.
Sin embargo, existen algunas convenciones que ayudan a simular constantes:
✅ Usar mayúsculas por convención
MAX_MANA = 100
Esta es una convención común en Python para indicar que un valor no debería cambiarse, aunque nada impide modificarlo.
🔒 Inmutabilidad con Final
(Python 3.8+)
Desde Python 3.8, puedes usar Final
del módulo typing
para declarar que una variable no debe ser reasignada.
from typing import Final
SPIRIT_NAME: Final[str] = "Puck"
Aunque Final
no impide la reasignación en tiempo de ejecución, herramientas de análisis estático como mypy
pueden detectar usos incorrectos:
SPIRIT_NAME = "Muspel" # ⚠️ mypy: Cannot assign to final variable "SPIRIT_NAME"
Buenas prácticas
Si estás desarrollando bibliotecas o trabajando en proyectos colaborativos, usar Final
es una forma explícita de comunicar la intención de inmutabilidad.
Aunque no impide errores en tiempo de ejecución, ayuda a prevenirlos de forma anticipada gracias a herramientas como mypy
o Pyright.
🧱 Propiedades con decoradores
A diferencia de Kotlin, donde todas las variables son propiedades (ya sea dentro o fuera de una clase), en Python solo puedes declarar propiedades dentro de clases y debes definirlas explícitamente con métodos especiales.
class Foo:
__value: T
@property
def value(self) -> T: ...
@value.setter
def value(self, value: T) -> None: ...
@value.deleter
def value(self) -> None: ...
Explicación de la sintaxis
@property
convierte el métodovalue
en una propiedad de solo lectura.@value.setter
permite asignar un nuevo valor conobj.value = ...
.@value.deleter
permite eliminar la propiedad condel obj.value
.- Los tres métodos deben tener el mismo nombre (
value
) para formar una única propiedad.
Este enfoque te permite encapsular acceso, validación o lógica de eliminación, de forma similar a los get()
y set()
personalizados en Kotlin.
📚 Ejemplo práctico: Exponer una lista como inmutable
Supón que estás desarrollando una clase Author
y deseas que otras personas puedan consultar las obras del autor, pero sin poder modificarlas directamente.
class Author:
__name: str
__works: list[str]
def __init__(self, name: str, works: list[str]):
self.__name = name
self.__works = works
@property
def works(self) -> tuple[str, ...]:
return tuple(self.__works)
¿Qué acabamos de hacer?
El atributo interno __works
almacena una lista mutable de obras.
Sin embargo, el método getter lo expone como una tupla, que es inmutable.
Esto permite que quien use la clase pueda acceder a las obras (author.works
), pero no podrá modificarlas directamente, como reemplazar o agregar elementos.
Es un patrón útil cuando quieres mantener la inmutabilidad en la interfaz pública, sin renunciar a la eficiencia de las listas internamente.
✏️ Ejemplo práctico: Validar y controlar una propiedad editable
Supón que estás creando una clase User
y quieres permitir la lectura y edición del nombre, pero validando que no esté vacío. Además, quieres poder eliminar el nombre si es necesario.
class User:
__name: str
def __init__(self, name: str):
self.__name = name
@property
def name(self) -> str:
return self.__name
@name.setter
def name(self, value: str) -> None:
if not value.strip():
raise ValueError("Name cannot be empty")
self.__name = value
@name.deleter
def name(self) -> None:
self.__name = "Anonymous"
¿Qué acabamos de hacer?
@property
permite acceder auser.name
como si fuera un atributo común.@name.setter
se invoca cuando hacesuser.name = "Nuevo nombre"
, y valida que no esté vacío.@name.deleter
se activa condel user.name
, y en lugar de borrar el atributo, lo restablece a"Anonymous"
.
Este patrón te permite usar una sintaxis limpia y natural, mientras mantienes control sobre la lógica interna.
🆚 Resumen comparativo
Aspecto | Kotlin | Python |
---|---|---|
Declaración | Requiere val o var y especificar tipo (opcional con inferencia). | Asignación directa sin palabra clave ni tipo declarado. |
Mutabilidad | val (inmutable) y var (mutable). | Todas las variables son mutables por defecto. |
Control de mutabilidad | La referencia puede ser inmutable (val ), pero el contenido puede ser mutable. | La mutabilidad depende del tipo del objeto (int inmutable, list mutable). |
Constantes | val para referencias constantes, const val para constantes en tiempo de compilación. | No hay constantes reales; se usa convención (MAYÚSCULAS ) o Final (desde Python 3.8). |
Propiedades (dentro de clases) | Toda propiedad puede tener get /set personalizados con acceso controlado. | Uso explícito de decoradores @property , @setter y @deleter . |
Visibilidad del setter | Puede limitarse (ej. private set ). | No hay modificadores de acceso; se controla indirectamente con convención o encapsulación. |
Campos de respaldo / backing fields | Usa field para acceder al valor real en get /set . | Se accede directamente a atributos privados (ej. __name ) dentro de métodos. |
Vista inmutable de estructuras mutables | Exponer List<T> desde MutableList<T> (conversión implícita). | Exponer tuple desde list para garantizar inmutabilidad. |
Validación en setters | Se usa en set(value) con funciones como require . | Se usa en @setter con raise ValueError(...) . |
Detección de errores en tiempo de compilación | El compilador verifica asignaciones inválidas (val , tipo, etc.). | Requiere herramientas externas como mypy o Pyright. |
Orientación a inmutabilidad | Fuerte énfasis en inmutabilidad por defecto (val ). | Enfocado en flexibilidad; la inmutabilidad es opcional y por convención. |
Beneficios de Python
- Sintaxis simple y directa para declarar variables sin necesidad de palabras clave adicionales.
Esto reduce el ruido visual y permite concentrarse en la lógica del programa, lo cual es útil en prototipos, scripts o enseñanza.
Aun cuando sacrifica la expresividad explícita de la intención (como distinguir entreval
yvar
), favorece la fluidez al escribir código rápidamente. - Flexibilidad total para reasignar variables o cambiar tipos en tiempo de ejecución.
Esta libertad es valiosa en escenarios dinámicos como procesamiento de datos, scripting, pruebas rápidas o metaprogramación.
Aunque puede dificultar el seguimiento del flujo de tipos, permite escribir código más adaptable y reutilizable sin rigidez estructural. - Sistema de propiedades mediante decoradores permite encapsular lógica con una sintaxis clara.
Aunque más explícita que en Kotlin, ofrece un control fino sobre lectura, escritura y eliminación de atributos. - Ideal para scripting, prototipado rápido y enseñanza por su bajo nivel de complejidad inicial.
Los principiantes pueden centrarse en conceptos esenciales sin verse abrumados por la sintaxis del lenguaje. - Compatibilidad con anotaciones opcionales (
Final
, tipos) permite reforzar buenas prácticas con herramientas externas.
Esto facilita una adopción progresiva de prácticas robustas sin imponerlas desde el inicio.
Limitaciones de Python
- No existe una forma nativa de restringir la reasignación o mutabilidad de variables.
Esto dificulta expresar la intención de inmutabilidad en la interfaz pública de una biblioteca. Aunque existen convenciones (MAYÚSCULAS
) y herramientas comoFinal
, ninguna impone restricciones reales en tiempo de ejecución. - Las garantías de tipo o de estado son opcionales y dependen de herramientas externas.
Python no valida las anotaciones de tipo ni impide errores como asignar un valor inesperado.
Esto puede llevar a fallos en tiempo de ejecución que, en lenguajes como Kotlin, se detectan en compilación. - Las propiedades deben definirse manualmente con decoradores.
Aunque poderosas, requieren más código explícito y repetitivo que en Kotlin, donde cada variable es una propiedad conget/set
implícitos desde el inicio. - No hay modificadores de acceso reales (
private
,protected
).
El uso de convenciones como__atributo
ayuda a ocultar implementación, pero no impide el acceso desde fuera. Esto complica la encapsulación y puede dificultar la evolución segura de bibliotecas. - La flexibilidad del lenguaje dificulta razonar formalmente sobre el estado de los objetos.
Al permitir reasignaciones y cambios de tipo en cualquier momento, se vuelve más difícil garantizar invariantes internas o aplicar transformaciones seguras sin pruebas exhaustivas o validaciones adicionales. - La falta de inmutabilidad por defecto complica el estilo funcional.
En programación funcional, la inmutabilidad es clave para componer funciones puras y evitar efectos colaterales.
Como Python permite mutar estructuras y reasignar nombres libremente, es más fácil introducir errores sutiles y más difícil aplicar enfoques funcionales de forma segura y expresiva.
🎯 Conclusiones
A lo largo de esta lección exploramos cómo se declaran y gestionan las variables en Python, y cómo este modelo difiere profundamente del enfoque expresivo y seguro de Kotlin.
Python privilegia la simplicidad y flexibilidad, permitiendo reasignaciones sin restricciones y eliminando la necesidad de palabras clave como val
o var
. Esto facilita la escritura de código rápido y dinámico, especialmente útil en scripts, prototipos y enseñanza. Sin embargo, también sacrifica garantías importantes como la inmutabilidad por defecto, la validación de tipos en compilación o el control explícito de visibilidad y mutabilidad.
En contraste con Kotlin, donde cada variable es también una propiedad capaz de encapsular lógica de forma declarativa, en Python se requiere definir manualmente cada aspecto mediante decoradores. Esto otorga poder, pero también impone más esfuerzo y atención al detalle para lograr un diseño robusto.
Finalmente, vimos cómo algunas herramientas del ecosistema —como Final
, mypy
o @property
— permiten recuperar parte de esa expresividad, aunque nunca con la misma fuerza ni inmediatez que en un lenguaje estáticamente tipado y orientado a la inmutabilidad por defecto.
🔑 Puntos clave
- En Python, una variable se crea al asignarle un valor: no necesita declaración previa ni palabra clave.
- No hay distinción nativa entre variables mutables e inmutables; toda variable puede ser reasignada.
- La inmutabilidad depende del tipo del objeto (por ejemplo,
int
es inmutable;list
es mutable). - No existe soporte real para constantes, pero se pueden simular con convenciones (
MAYÚSCULAS
) oFinal
. - Las propiedades se implementan con decoradores (
@property
,@setter
,@deleter
), lo que permite encapsular validaciones y lógica de acceso. - Python no impone restricciones, pero sí ofrece herramientas opcionales para lograr mayor seguridad y expresividad.
🧰 ¿Qué nos llevamos?
Python ofrece un entorno flexible y accesible, ideal para quienes priorizan rapidez de desarrollo, exploración interactiva o enseñanza. Su sistema de variables permite escribir código sin fricciones, pero a costa de perder garantías que en otros lenguajes —como Kotlin— están integradas desde la base.
Este enfoque no es malo por sí mismo, pero te delega a ti, como quien diseña las bibliotecas, la responsabilidad de proteger tus invariantes. Tendrás que aplicar disciplina, convenciones, y herramientas adicionales si buscas ofrecer una API segura y mantenible.
Elegir entre flexibilidad y restricciones no es una cuestión de preferencia personal, sino de adecuación al problema y al contexto. En un script simple o una exploración de datos, la flexibilidad de Python brilla. En una biblioteca compartida y en evolución, podrías echar de menos las garantías de un sistema como el de Kotlin.
La clave es comprender qué te ofrece cada lenguaje, y cómo usar sus herramientas —y sus límites— a tu favor.
📖 ¿Con ganas de más?
🔥 Referencias recomendadas
- 🌐 “Python Constants: Improve Your Code’s Maintainability – Real Python” en Real Python :Este artículo ofrece una guía completa sobre el uso de constantes en Python para mejorar la legibilidad, mantenibilidad y seguridad del código. Explica qué son las constantes, por qué usarlas y cómo implementarlas en proyectos reales, a pesar de que Python no tiene una sintaxis nativa para constantes estrictas. Cubre buenas prácticas, uso de constantes predefinidas y estrategias para organizarlas (como módulos dedicados, archivos de configuración o variables de entorno). Además, presenta técnicas avanzadas para crear constantes verdaderamente inmutables usando clases,
@property
,namedtuple
,@dataclass
y más.