La metaprogramación en Python te permite controlar cómo se crean y configuran tus objetos antes incluso de que existan. Si ya usaste __init__ para construir atributos en programación orientada a objetos, ahora toca dar el siguiente paso: entender cómo __new__ entra en escena para tomar el control de la instancia desde su origen.
Qué hace el método new frente al init
Cuando creas una clase en Python, hay dos métodos especiales que trabajan en cadena. Uno construye la instancia, el otro la inicializa. Y el orden importa.
El método __new__ es el responsable de crear una nueva instancia del objeto. Se ejecuta antes que __init__ y devuelve el objeto recién nacido. Después entra __init__, que recibe esa instancia y le asigna los atributos que tú definiste, como un factor de multiplicación o cualquier otro dato que necesite tu clase.
¿Qué diferencia hay entre new e init?__new__ crea la instancia y devuelve el objeto. __init__ recibe esa instancia ya creada y la inicializa con valores. Primero se ejecuta __new__, luego __init__.
Por qué new va antes que init en el código
Aunque __init__ sea el método que más conoces, cuando trabajas con __new__ la lógica de lectura cambia. Por buenas prácticas, __new__ se escribe al inicio de la clase porque ahí es donde nace la instancia. Solo después tiene sentido inicializarla.
Dentro de __new__ debes invocar a super() para que la clase padre genere el objeto base. Sin esa llamada, no hay instancia que devolver.
Cómo construir una clase generadora de multiplicadores
Imagina una clase que recibe un factor y multiplica cualquier número que le pases. Es un caso simple pero ideal para ver los dos métodos en acción.
El flujo es así:
Defines __new__ para crear la instancia y dejar un mensaje tipo Creando instancia con factor 5.
Defines __init__ para guardar el factor como atributo y mostrar Inicializando valor con factor igual a 5.
Creas un método que reciba un número y lo multiplique por el factor almacenado.
Cuando ejecutas multiplier = GeneradorMultiplicadores(5), el número 5 viaja primero a __new__ y luego a __init__. Si después llamas al método con el valor 10, obtienes 50 como resultado.
python
class GeneradorMultiplicadores:
def new(cls, factor):
print(f"Creando instancia con factor {factor}")
instancia = super().new(cls)
return instancia
def __init__(self, factor):print(f"Inicializando valor con factor igual a {factor}") self.factor= factor
def multiplicar(self, numero):return self.factor* numero
Verás tres salidas en orden. Primero el mensaje desde __new__ confirmando la creación. Luego el mensaje desde __init__ confirmando la inicialización. Y al final, el resultado de la multiplicación: 50.
Ese rastro en consola es útil cuando depuras o necesitas auditar cómo se están construyendo tus objetos en proyectos grandes.
Cuándo conviene usar metaprogramación en tus proyectos
Aquí viene lo interesante: no todas las clases necesitan __new__. La mayoría del tiempo, con __init__ te basta y te sobra.
La metaprogramación cobra sentido cuando trabajas en proyectos complejos donde necesitas controlar la creación de cada instancia, validar datos antes de construir el objeto, implementar patrones como singleton, o personalizar el comportamiento de clases que heredan de otras.
¿Siempre debo usar new al crear una clase? No. Úsalo solo cuando necesites controlar la creación misma del objeto, no su inicialización. Para casos comunes, __init__ es suficiente.
Usar metaprogramación sin necesidad agrega complejidad innecesaria a tu código. Evalúa el proyecto antes de decidir: si lo que necesitas es solo asignar atributos, quédate con el constructor clásico. Si requieres flexibilidad y control desde la creación misma, ahí es donde __new__ brilla.
¿En qué tipo de proyecto crees que tendría más sentido aplicar __new__? Cuéntame en los comentarios cómo lo usarías.
Este curso como muchos otros habría que reformularlo. Aprecio la vocación de la profesora pero creo faltó planificación. No se puede empezar una clase, por ejemplo de metaprogramación en python, sin explicar qué es la metaprogramación, qué problema resuelve o cuál es su utilidad, y pediría si no fuera mucho que no sólo se de un ejemplo sencillo sacado de la nada, sería mucho mejor que proveyeran ejemplos reales de utilidad práctica. En lo posible dentro de un mismo curso se podría ir trabajando el mismo ejemplo desde el comienzo de un problema real y distintas formas de solucionarlo, ir haciendo refactoring, o mostrando distintas aristas a un caso concreto y real.
Muy buen aporte.
Gracias por tu aporte!
No entendi la verdad como utilizarlos practicamente. No me gusto esta clase la verdad, deberia haber un botoncito de me gusta y NO me gusta.
Estoy de acuerdo.
En resumen:
__new__: Controla la creación del objeto.
__init__: Inicializa el objeto (configurando sus atributos).
__call__: Permite que la instancia de la clase actúe como una función.
No tengo ni idea de para que sirve esto, una clase a medias, si no es por los comentarios no me entero de que trata.
Concuerdo.
La metaprogramación en Python es una técnica que permite a los programas manipular o generar código durante su ejecución. Esto se puede lograr a través de varias funcionalidades del lenguaje, como las clases, los decoradores, las funciones de alto orden y los metaclases. Aquí tienes un resumen de las principales técnicas de metaprogramación en Python:
### 1. **Decoradores**
Los decoradores son una forma de modificar el comportamiento de una función o método. Puedes crear decoradores para agregar funcionalidades adicionales sin modificar el código original.
def mi\_decorador(func):  def envoltura():  print("Algo se está haciendo antes de llamar a la función.")  func()  print("Algo se está haciendo después de llamar a la función.")  return envoltura@mi\_decorador
defsaludar():  print("¡Hola!")saludar()
### 2. **Funciones de alto orden**
Las funciones de alto orden son aquellas que pueden recibir otras funciones como argumentos o devolverlas como resultados. Esto permite crear comportamientos dinámicos.
Las metaclases son clases de clases, lo que significa que definen cómo se crean las clases. Puedes crear una metaclase para modificar la creación de clases.
classMiMeta(type):  def \_\_new\_\_(cls, nombre, bases, dct):  dct\['nuevo\_atributo'] = 'Soy un nuevo atributo'  return super().\_\_new\_\_(cls, nombre, bases, dct)classMiClase(metaclass=MiMeta):  passobjeto = MiClase()print(objeto.nuevo\_atributo)# Salida: Soy un nuevo atributo
### 5. **Reflexión y introspección**
Python permite inspeccionar objetos en tiempo de ejecución, lo que puede ser útil para metaprogramación. Puedes utilizar funciones como getattr(), setattr(), hasattr() y dir().
- Permite crear código más flexible y reutilizable.
- Facilita la creación de bibliotecas y frameworks.
- Puede simplificar el código al evitar duplicaciones.
**Desventajas:**
- Puede hacer que el código sea más difícil de entender.
- El uso excesivo puede llevar a un rendimiento reducido.
- Puede complicar la depuración debido a su naturaleza dinámica.
La metaprogramación es una poderosa herramienta en Python, pero debe usarse con cuidado para mantener la claridad y la mantenibilidad del código.
Gracias por tu aporte!
En la clase se vieron varios conceptos que no quedaron claros y tuve que investigar aparte, aquí dejos agunas cosas que creo que pueden ayudar a entender mejor:
Todas las clases heredan de una superclase llamada object
El método __new__ es el que realmente crea las instancias y ya esta definido en object, asi que cuando creamos una instancia de cualquier clase, internamente se esta llamando el metodo new de object para crear la instancia
<!---->
Solo es necesario definir el método new en una clase cuado se quiere cambiar la forma en que se crean las instancias, por ejemplo al hacer metaprogramación
Siempre que se defina new es necesario tener como primer parametro cls (al igual que en los otros métodos es self) que representa a la clase de la instancia a crear
Para cambiar la forma en que se crea una instancia con new, es necesario llamar al método new de object, esto se hace con super(subclase,cls).__new__(cls), en este caso subclase es MultiplierFactory porque es subclase de object
call es un método especial que permite que una instancia de la clase sea llamada como una función
🫤La verdad no entendí esta clase, ahora me toca ir a otra parte a investigar sobre la meta programación en Python, creo que esta clase se debería volver a hacer o hacer una clase nueva que amplíe la información sobre este tema.
EL método __ call __ , tiene como única relevancia hacer la multificación??? se llama " call " como se puede llammar " Multiply " ???
Hice la prueba utilizando el método mult, sin embargo me ocasiono error, tal vez al estar usando la meta programación se debe de llamar directamente a la función.```js
Buenos compañeros no sé si será esta una respuesta para ti los métodos mágicos no se puede renombrar y "call", es uno de ellos si quieres hacer algo parecido a lo que tu indicas puedes pasar lo siguiente:
classMultiplierFactory:def__new__(cls, factor:int):print(f"Creando instancia con factor {factor}")returnsuper(MultiplierFactory, cls).__new__(cls)def__init__(self, factor:int):print(f"Inicializando con factor {factor}") self.factor = factor
#def __call__(self, number: int) -> int:#return number * self.factordefmultipli(self, number:int)->int:return number * self.factor
multiplier = MultiplierFactory(5)result = multiplier.multipli(10)print(result)```Te dará el mismo resultado, espero que te sirva. Un saludo.
La metaprogramación en Python se refiere a la práctica de escribir código que genera o modifica código en tiempo de ejecución. En otras palabras, es un tipo de programación en la que el programa puede manipular su propia estructura y comportamiento.
Concepto
La metaprogramación permite a los desarrolladores crear programas más dinámicos y flexibles. Se utiliza para automatizar tareas repetitivas, generar código automáticamente, y modificar el comportamiento de las clases y funciones durante la ejecución del programa.
Utilidad
La metaprogramación es útil en varias situaciones, como:
Generación de Código: Crear nuevas funciones o métodos dinámicamente.
Modificación de Clases y Funciones: Cambiar el comportamiento de clases y funciones existentes sin modificar su código fuente.
Decoradores y Metaclases: Utilizar decoradores para añadir funcionalidades a funciones y métodos, y metaclases para personalizar la creación y comportamiento de clases.
Ejemplos
Uso de Decoradoresdef mi_decorador(func):
def funcion_envuelta(*args, **kwargs):
print("Funcionalidad añadida antes de la función.")
resultado = func(*args, **kwargs)
print("Funcionalidad añadida después de la función.")
return resultado
return funcion_envuelta
@mi_decorador
def funcion():
print("Esta es la función original.")
funcion(): Los decoradores son una forma común de metaprogramación en Python. Permiten añadir comportamiento a funciones o métodos de manera declarativa.python
def mi_decorador(func): def funcion_envuelta(*args,**kwargs):print("Funcionalidad añadida antes de la función.") resultado =func(*args,**kwargs)print("Funcionalidad añadida después de la función.")return resultado
return funcion_envuelta
@mi_decorador
def funcion():print("Esta es la función original.")funcion()
Metaclases: Una metaclase es una clase de clases que define cómo se crean y se comportan las clases. Permiten modificar dinámicamente la estructura y comportamiento de las clases.
classMiMetaClase(type): def __new__(cls, nombre, bases, dic): dic['atributo_agregado']="Atributo añadido por la metaclase"returnsuper().__new__(cls, nombre, bases, dic)classMiClase(metaclass=MiMetaClase): def __init__(self, valor): self.valor= valor
instancia =MiClase(10)print(instancia.atributo_agregado) # Imprime:Atributo añadido por la metaclase
Ventajas
Flexibilidad: Permite escribir código más flexible y adaptable.
Reducción de Redundancia: Automatiza tareas repetitivas, reduciendo la duplicación de código.
Abstracción: Facilita la creación de abstracciones más potentes y reutilizables.
Optimización del Código: Permite optimizar el rendimiento al generar y modificar código en tiempo de ejecución.
Desventajas
Complejidad: La metaprogramación puede hacer que el código sea más complejo y difícil de entender.
Errores en Tiempo de Ejecución: Al modificar el comportamiento del código en tiempo de ejecución, es más probable que ocurran errores difíciles de detectar.
La metaprogramación es una herramienta poderosa que, cuando se utiliza adecuadamente, puede mejorar significativamente la calidad y la eficiencia del código. Sin embargo, es importante usarla con cuidado para evitar introducir complejidad innecesaria.
Creo que podrían mejorar este curso explicando para que funciona y que es lo que se va a aprender en esa clase, así como poner ejemplos prácticos y explicar que es exactamente lo que hace.
Algunas clases han sido solo presentar lo que se va a ver y poner un ejemplo.
Se que viene la explicación en la sección de recursos, pero tambien seria bueno mencionarlo y hablar un poco sobre eso en la clase.
Cool! me gusto ademas que tiene ordenado todo en carpetas
La metaprogramación no se entiende en una clase de 03:59 minutos, mucho menos cuando los ejemplos de la clase nada que ver, con esta clase ni si quiera se tiene una noción de lo que es la metaprogramación, para mi se deberia dedicar una sesión entera a este tema, la verdad siento que mientras se grabo esta clase, se cometieron errores, por ejemplo con el orden lógico de los métodos:
def __new__
```y: 
```js
def __init__
```ademas, tampoco vi la explicación de `type y object`
¿A alguien más le pasa que el reto les sale antes de que den la información necesaria para saber las respuestas? Ya me ha pasado en 2 clases
Sí, pasa mucho
La metaprogramación es un tema demasiado importante, como para que la clase dure sólo 4 minutos, qué pasó aquí jaja
Compañeros, les comparto esta joya por si se les están complicando las clases, , allí encontrarán varias respuestas a sus preguntas!
¿Puedo usar esto para el patrón Singleton?
Absolutamente, de hecho, es el caso de uso más clásico y elegante para este método en Python. El patrón Singleton garantiza que una clase tenga una única instancia global durante toda la ejecución del programa, lo cual es ideal para gestionar conexiones a bases de datos o configuraciones globales.
Para lograrlo con __new__, simplemente creas un atributo de clase (por ejemplo, _instancia = None). Cuando alguien intenta crear un objeto, __new__ verifica si ese atributo ya tiene una instancia guardada. Si está vacío, llama a super().__new__(cls) para crearla y la guarda. Si ya existe, simplemente retorna la instancia previamente guardada en lugar de crear una nueva. De esta forma, sin importar cuántas veces llames a la clase en diferentes partes de tu código, siempre estarás interactuando exactamente con el mismo objeto en memoria, optimizando recursos y evitando conflictos de estado.
¿Cómo controlo la creación de múltiples instancias?
Puedes controlar la creación de instancias utilizando __new__ como un gestor de caché o un limitador (pool). En lugar de permitir que el sistema cree objetos de forma ilimitada y consuma toda tu memoria RAM, puedes interceptar la petición antes de que ocurra.
Imagina que estás desarrollando un videojuego y necesitas generar enemigos. En lugar de instanciar un nuevo enemigo cada vez (lo que es costoso para el procesador), puedes usar __new__ para revisar una lista interna de 'enemigos inactivos'. Si hay uno disponible, __new__ lo recicla y lo devuelve; si no hay ninguno, entonces sí invoca a super() para crear uno nuevo.
Para implementar esto, defines una estructura de datos a nivel de clase (como un diccionario o una lista) y programas la lógica condicional dentro de __new__. Esto te otorga un control absoluto sobre el ciclo de vida de los objetos, asegurando que tu aplicación escale de manera eficiente.
"""Valida que el JSON sea correcto o intenta recuperar del backup."""
if os.path.exists(self.archivo_datos):
try:
with open(self.archivo_datos, 'r', encoding="utf-8") as f:
self.usuarios = json.load(f)
print(f"✅ Datos de '{self.nombre_empresa}' cargados.")
except json.JSONDecodeError:
print("🚨 ARCHIVO CORRUPTO DETECTADO.")
self._intentar_recuperacion()
def _intentar_recuperacion(self):
"""Si el principal falla, intenta cargar el backup."""
if os.path.exists(self.archivo_backup):
print("🔄 Intentando recuperar datos desde el backup...")
try:
with open(self.archivo_backup, 'r', encoding="utf-8") as f:
self.usuarios = json.load(f)
print("❇️ Recuperación exitosa. Se restauraron los datos previos.")
except:
print("❌ El backup también está corrupto.")
sys.exit(1)
else:
print("❌ No existe un backup disponible. El sistema se cerrará.")
sys.exit(1)
# --- USO ---
app = EmpresaApp("Tech Global")
El método __call__ en Python permite que una instancia de una clase se comporte como una función. Al definir este método, puedes invocar objetos de esa clase directamente como si fuesen funciones. Esto es útil para crear clases que necesitan un comportamiento de llamada, como en el caso de funciones callback o para crear objetos que encapsulan lógica de negocio específica.
En este caso, multiply_by_2 es un objeto que se puede llamar como función, multiplicando cualquier número por 2.
Recomiendo consultar:
La metaprogramación es una técnica en programación que permite a los programas manipular su propia estructura y comportamiento. En Python, se utiliza a través de métodos especiales, como __new__ y __init__, que permiten personalizar el proceso de creación de objetos. __new__ se encarga de crear la instancia de la clase, mientras que __init__ inicializa los atributos. Esta técnica es útil para crear clases flexibles y controladas, aunque no siempre es necesaria en proyectos simples.