Comparación, operaciones, contenedores, privacidad, propiedades y herencia
En esta parte implementamos comparación, aritmética, contenedores personalizados, miembros privados por convención, propiedades y herencia (incluida la clase base object y la sobrescritura de métodos).
__eq__, __lt__, etc.)class Punto:
def __init__(self, x, y):
self.x = x; self.y = y
def __eq__(self, other):
return isinstance(other, Punto) and (self.x, self.y) == (other.x, other.y)
def __lt__(self, other):
return (self.x, self.y) < (other.x, other.y)
print(Punto(1,2) == Punto(1,2))
print(Punto(0,5) < Punto(1,0))Nota: implementar lo necesario según el orden total o parcial deseado.
__add__, __sub__)class Vector:
def __init__(self, x, y):
self.x = x; self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
v = Vector(1,2) + Vector(3,4)
w = Vector(5,5) - Vector(2,1)
print((v.x, v.y), (w.x, w.y))Criterio: retornar nuevas instancias (inmutabilidad semántica del resultado).
__len__, __getitem__)class Coleccion:
def __init__(self, datos):
self._datos = list(datos)
def __len__(self):
return len(self._datos)
def __getitem__(self, idx):
return self._datos[idx]
c = Coleccion([10, 20, 30])
print(len(c), c[1])Idea: implementar protocolos hace que el objeto sea interoperable con Python (for, slicing, etc.).
_interno y __mangleclass Caja:
def __init__(self, valor):
self._valor = valor # convención: “protegido”
self.__clave = "secreto" # name mangling: _Caja__clave
def abrir(self, clave):
return clave == self.__clave
c = Caja(42)
print(c._valor, c._Caja__clave) # se puede acceder, pero es mala prácticaNota: Python confía en convenciones más que en restricciones fuertes.
@property)class Persona:
def __init__(self, nombre):
self._nombre = nombre
@property
def nombre(self):
return self._nombre
@nombre.setter
def nombre(self, nuevo):
if not nuevo.strip():
raise ValueError("Nombre vacío no permitido")
self._nombre = nuevo
p = Persona("Ana")
p.nombre = "Ana María"
print(p.nombre)Ventaja: interfaz de atributo con validación/cómputo bajo el capó.
class Animal: # hereda de object implícitamente
def hablar(self):
return "..."
class Perro(Animal): # herencia simple
def hablar(self): # sobrescritura
return "Guau"
class Gato(Animal):
def hablar(self):
return "Miau"
for a in (Perro(), Gato(), Animal()):
print(a.hablar())Punto clave: la clase base object está en la raíz del MRO; la sobrescritura permite comportamiento especializado.
@property frente a exponer atributos públicos sin control?