En esta sección enumero algunas características que considero relevantes y las comparo con Java.
1. Sintaxis Clara y Legible
Python fue diseñado con una sintaxis simple y práctica, menos rigurosa que en Java u otros lenguajes. Su sintaxis utiliza indentación (espacios en blanco) para definir bloques de código, en lugar de llaves o palabras clave:
def calcular_factorial(n):
if n == 0 or n == 1:
return 1
else:
return n * calcular_factorial(n - 1)
Esta característica hace que el código Python sea visualmente limpio y fácil de entender, supongo que incluso para personas sin experiencia en programación, personalmente tampoco me complica escribir más código como en Java pero se agradece la simpleza de Python.
En java puedes escribir código que cumpla con la sintaxis pero visualmente puede quedar desordenado.
public static int calcularFactorial(int n) { if (n == 0 || n == 1) { return 1; } else { return n * calcularFactorial(n - 1); } }
Los IDE pueden ordenar el código y no hay problema, de todas formas me parece bien que la sintaxis te obligue a ser ordenado ya que el programador no siempre será prolijo (me incluyo) y tampoco va a utilizar la función de ordenamiento automático.
public static int calcularFactorial(int n) {
if (n == 0 || n == 1) {
return 1;
} else {
return n * calcularFactorial(n - 1);
}
}
2. Tipado Dinámico
Python es un lenguaje de tipado dinámico, lo que significa que no es necesario declarar explícitamente el tipo de las variables:
x = 5 # x es un entero
x = "texto" # ahora x es una cadena
x = [1, 2, 3] # ahora x es una lista
A partir de Python 3.5, se introdujeron los “type hints” opcionales, que permiten añadir información de tipos sin perder la flexibilidad del tipado dinámico:
def saludar(nombre: str) -> str:
return f"Hola, {nombre}"
En Java la declaración es estricta para cada tipo de dato:
// Tipos primitivos
int edad = 37;
double monto = 45000.50;
float precio = 19.99f;
long poblacion = 7800000000L;
boolean esActivo = true;
char inicial = 'G';
byte nivel = 10;
short cantidad = 1000;
// Strings (objetos)
String nombre = "Gonzalo";
String apellido = "Rojas";
// Arrays
int[] numeros = {1, 2, 3, 4, 5};
String[] nombres = new String[3];
double[][] matriz = new double[3][3];
// Objetos
Date fecha = new Date();
List<String> lista = new ArrayList<>();
// Constantes (final)
final double PI = 3.14159;
final int MAX_INTENTOS = 3;
// Declaración múltiple del mismo tipo
int x = 10, y = 20, z = 30;
// Variables sin inicializar (valor por defecto)
int contador; // Se inicializa con 0
String texto; // Se inicializa con null
3. Multiparadigma
Python soporta múltiples paradigmas de programación, a continuación un ejemplo de los más comunes (comparando Python con Java).
Programación Orientada a Objetos:
class Perro:
def __init__(self, nombre):
self.nombre = nombre
def ladrar(self):
return f"{self.nombre} dice ¡Guau!"
public class Perro {
private String nombre;
public Perro(String nombre) {
this.nombre = nombre;
}
public String ladrar() {
return this.nombre + " dice ¡Guau!";
}
}
Programación Funcional:
numeros = [1, 2, 3, 4, 5]
cuadrados = list(map(lambda x: x**2, numeros))
pares = list(filter(lambda x: x % 2 == 0, numeros))
List<Integer> numeros = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> cuadrados =numeros.stream()
.map(x -> x * x).collect(Collectors.toList());
List<Integer> pares =numeros.stream()
.filter(x -> x % 2 == 0)
.collect(Collectors.toList());
Programación Procedural:
def procesar_datos(datos):
resultado = []
for item in datos:
resultado.append(item * 2)
return resultado
public static List<Integer> procesarDatos(List<Integer> datos {
List<Integer> resultado = new ArrayList<();
for(Integer item : datos) {
resultado.add(item * 2);
}
return resultado;
}
4. Extensibilidad e Integración
Python puede ser extendido fácilmente con código en C/C++ para operaciones que requieren alto rendimiento:
# Usando una extensión C
import numpy as np # NumPy usa C internamente
array = np.array([1, 2, 3, 4, 5])
También puede integrarse con otros lenguajes:
- Jython: Python en la JVM (Java)
- IronPython: Python en .NET
- PyPy: Implementación JIT de Python
- Cython: Compilador Python a C
5. Programación Asíncrona
Python 3.5+ incluye soporte nativo para programación asíncrona con async/await:
import asyncio
async def obtener_datos(id):
await asyncio.sleep(1) # Simula operación I/O
return f"Datos de {id}"
async def main():
resultados = await asyncio.gather(
obtener_datos(1),
obtener_datos(2),
obtener_datos(3)
)
print(resultados)
asyncio.run(main())
Esta característica es fundamental para aplicaciones web modernas y procesamiento concurrente eficiente.
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.List;
import java.util.stream.Collectors;
public class EjemploAsyncCompacto {
public static CompletableFuture<String> obtenerDatos(int id) {
return CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Datos de " + id;
});
}
public static void main(String[] args) {
List<Integer> ids = List.of(1, 2, 3);
// Crear todas las tareas asíncronas
List<CompletableFuture<String>> tareas = ids.stream()
.map(id -> obtenerDatos(id))
.collect(Collectors.toList());
// Esperar y obtener todos los resultados
List<String> resultados = tareas.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
System.out.println(resultados);
}
}
En Python es claramente más simple y directo, mientras que Java requiere código más explicito.
6. Introspección y Reflexión
Python permite examinar y modificar objetos en tiempo de ejecución:
class MiClase:
def metodo(self):
pass
obj = MiClase()
# Introspección
print(type(obj)) # <class '__main__.MiClase'>
print(dir(obj)) # Lista de atributos y métodos
print(hasattr(obj, 'metodo')) # True
# Reflexión
setattr(obj, 'nuevo_atributo', 42)
print(obj.nuevo_atributo) # 42
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
// Definir la clase
class MiClase {
public void metodo() {
// método vacío
}
}
public class EjemploReflexion {
public static void main(String[] args) {
MiClase obj = new MiClase();
// INTROSPECCIÓN
// Obtener el tipo (equivalente a type(obj))
Class<?> clase = obj.getClass();
// Listar métodos (equivalente a dir(obj))
Method[] metodos = clase.getMethods();
for (Method metodo : metodos) {
System.out.println(" " + metodo.getName());
}
// Listar campos/atributos
Field[] campos = clase.getDeclaredFields();
for (Field campo : campos) {
System.out.println(" " + campo.getName());
}
// Verificar si tiene un método (equivalente a hasattr)
boolean tieneMetodo = false;
try {
clase.getMethod("metodo");
tieneMetodo = true;
} catch (NoSuchMethodException e) {
tieneMetodo = false;
}
// REFLEXIÓN
// Java no permite agregar atributos dinámicamente como Python
// Pero se puede usar un Map para simular este comportamiento
ObjetoConAtributosDinamicos objDinamico = new ObjetoConAtributosDinamicos();
objDinamico.setAtributo("nuevo_atributo", 42);
System.out.println("nuevo_atributo: " + objDinamico.getAtributo("nuevo_atributo"));
// Salida: 42
}
}
// Clase que simula atributos dinámicos usando un Map
class ObjetoConAtributosDinamicos {
private Map<String, Object> atributosDinamicos = new HashMap<>();
public void metodo() {
// método vacío
}
// Equivalente a setattr
public void setAtributo(String nombre, Object valor) {
atributosDinamicos.put(nombre, valor);
}
// Equivalente a getattr
public Object getAtributo(String nombre) {
return atributosDinamicos.get(nombre);
}
// Equivalente a hasattr
public boolean tieneAtributo(String nombre) {
return atributosDinamicos.containsKey(nombre);
}
}
En Java no se pueden agregar atributos nuevos a una clase en tiempo de ejecución como en Python, porque Java es estáticamente tipado y la estructura de clases se define en compilación.