Mecanismos de instanciación y convenciones de objetos en Python: __new__, __init__, cls y self

Roles y secuencia de __new__ frante a __init__

En el ciclo de vida de un objeto dentro de Python, estos métodos dunder operan en fases distintas pero concatenadas:

  • __new__: Actúa como constructor primario. Al ser un método estático, recibe la clase destino mediante cls, reserva el espacio de memoria necesario y retorna la referencia al nuevo objeto. Se ejecuta antes de que la instancia sea accesible.
  • __init__: Funciona como inicializador secundario. Opera sobre el objeto ya retornado por __new__ y permite asignar valores a atributos específicos. Nunca debe retornar nada distinto a None.

El interprete une ambos pasos: lo que devuelve __new__ se pasa automáticamente como primer argumento (self) hacia __init__. Si __new__ omite la devolución o retorna un valor inesperado, la fase de inicialización podría saltarse o fallar.

Reglas de implementación

  • Solo las clases de estilo moderno (heredan de object o son clases base en Python 3) implementan __new__ de forma consistente.
  • __new__ exige al menos un parámetro cls, suministrado internamente.
  • Es obligatorio retornar una instancia. Lo habitual es delegar en la clase padre: super().__new__(cls).
  • Si se retorna una instancia de otra clase distinta desde __new__, Python invocará el __init__ correspondiente a esa clase destino, ignorando completamente el inicializador de la clase declarada.
  • Por defecto, si no se sobrescribe __new__, la jerarquía de herencia remonta hasta object.__new__().

Comportamiento sin retorno explícito

class ConstructorBase:
    def __new__(cls):
        print("Fase de reserva de memoria activada")
        
    def __init__(self):
        print("Configuración de atributos iniciada")

ConstructorBase()
# Salida:
# Fase de reserva de memoria activada

Cadenado correcto entre fases

class ConstructorBase:
    def __new__(cls):
        return super().__new__(cls)

    def __init__(self):
        print("Configuración de atributos iniciada")

ConstructorBase()
# Salida:
# Configuración de atributos iniciada

Control dinámico del tipo retornado

class EntidadA:
    def __str__(self):
        return "Instancia de Tipo-A"

class ControladorB:
    bandera = True
    
    def __new__(cls):
        if cls.bandera:
            return super().__new__(EntidadA)
        return super().__new__(cls)
    
    def __init__(self):
        pass

print(ControladorB())
# Salida:
# Instancia de Tipo-A

Nomenclatura funcional: cls y self

Aunque el lenguaje permite identificadores personalizados, PEP 8 estandariza cls y self para garantizar legibilidad en proyectos colaborativos.

Uso de cls

Se emplea exclusivamente en métodos declarados con el decorador @classmethod. El primer parámetro hace referencia a la clase llamante, no a un objeto particular. Esto facilita operaciones dependientes del estado de la clase misma, como fábricas internas o lectura de constantes compartidas.

class GestorClase:
    prefijo = "SYS_"

    @classmethod
    def obtener_registro(cls, veces=2):
        return f"{cls.prefijo}" * veces

print(GestorClase.obtener_registro(3))
# Salida:
# SYS_SYS_SYS_

Uso de self

Corresponde a los métodos de instancia normales. Este primer parámetro apunta al objeto concreto que invoca la función, permitiendo manipular datos encapsulados exclusivos de esa instancia.

Métodos estáticos (@staticmethod)

Carecen de enlace automático a ninguna clase ni objeto. Se comportan como funciones utilitarias alojadas dentro del namespace de una clase por organización temática. No reciben ni cls ni self.

modo_test = False

class ValidadorInterno:
    @staticmethod
    def verificar_entorno():
        return modo_test

    def ejecutar_prueba(self):
        if self.verificar_entorno():
            print("Ejecutando escenario de depuración")
        else:
            print("Modo producción activo")

instancia = ValidadorInterno()
instancia.ejecutar_prueba()

Etiquetas: Python programación-orientada-a-objetos metodos-dunder classmethod staticmethod

Publicado el 9-16 15:05