σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyRutas
Ctrl K
AO
+1,2 k estudiantes
Iniciar sesiónUnirse ↗
Rutas
AO
+1,2 k estudiantes
Iniciar sesión
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Ruta de Python›Módulo 1 · Fundamentos de Python para quants›Tema 1.27·~40 minPrincipiante

Métodos especiales (__repr__, __eq__)

Posición en la rutaMódulo 1 de 11 · Tema 27 de 33
1.27 Métodos especiales (__repr__, __eq__)
—Puntuación del lab— / 100XP total—Racha—

Hacer que tus objetos se comporten como tipos incorporados

Imprime un objeto simple y Python muestra algo como <__main__.Position object at 0x7f3a>, y Position("A", 1) == Position("A", 1) es False porque por defecto dos objetos son iguales solo si son exactamente el mismo objeto. Los métodos especiales (llamados dunder, por los guiones bajos dobles) permiten que tu clase se integre en la sintaxis de Python: __repr__ controla cómo se muestra un objeto, __eq__ controla ==, __add__ controla +, __lt__ controla <, etc. Nunca los llamas directamente; Python los llama cuando usas repr(x), a == b, a + b o sorted(items).

class Plain:
    def __init__(self, cents):
        self.cents = cents

a, b = Plain(500), Plain(500)
print(a == b)                 # False: different objects
print(a.cents == b.cents)     # True
print("object at 0x" in str(a))   # True: the default display is unhelpful

__repr__: mostrar el objeto con claridad

__repr__ devuelve una cadena que describe el objeto para desarrolladores. Por convención se parece al código que lo construiría: Money(1999, 'USD'). Las listas, el depurador y los mensajes de error la usan, lo que hace los errores mucho más legibles. print(x) y str(x) también usan __repr__ salvo que definas además __str__ para un texto más bonito de cara al usuario. Debe devolver la cadena, no imprimirla, y {self.currency!r} en una f-string da la forma entrecomillada de un atributo de texto.

class Money:
    def __init__(self, cents, currency="USD"):
        self.cents = cents
        self.currency = currency

    def __repr__(self):
        return f"Money({self.cents}, {self.currency!r})"

price = Money(1999)
print(price)                    # Money(1999, 'USD')
print([Money(5), Money(7, "EUR")])  # [Money(5, 'USD'), Money(7, 'EUR')]

__eq__ y __hash__: ¿qué significa igual?

__eq__(self, other) decide self == other. Compara los campos que definen la identidad y, cuando other no es del tipo esperado, devuelve el valor especial NotImplemented (no False): Python prueba entonces el otro lado y por fin responde False él mismo, así que Money(1) == 5 es seguro. Definir __eq__ desactiva el hash: los objetos ya no pueden ser miembros de un conjunto ni claves de diccionario a menos que definas también __hash__ de forma coherente, por ejemplo hash((self.cents, self.currency)).

class Money:
    def __init__(self, cents, currency="USD"):
        self.cents = cents
        self.currency = currency

    def __eq__(self, other):
        if not isinstance(other, Money):
            return NotImplemented            # let Python decide
        return self.cents == other.cents and self.currency == other.currency

    def __hash__(self):
        return hash((self.cents, self.currency))

print(Money(500) == Money(500))      # True
print(Money(500) == Money(500, "EUR"))  # False
print(Money(500) == 500)             # False, no error
print(len({Money(1), Money(1)}))     # 1: usable in sets now

Operadores y orden

__add__(self, other) da + a tu clase. Devuelve un objeto nuevo en lugar de cambiar self, y rechaza lo absurdo: sumar dólares y euros debe lanzar ValueError, sumar un número suelto debe devolver NotImplemented. __lt__(self, other) da <, y con eso basta para que sorted(), min() y max() ordenen tus objetos, porque solo necesitan preguntar «¿a es menor que b?». Añade también __le__, __gt__, __ge__, o deja que functools.total_ordering los derive.

class Money:
    def __init__(self, cents, currency="USD"):
        self.cents = cents
        self.currency = currency

    def __repr__(self):
        return f"Money({self.cents}, {self.currency!r})"

    def __add__(self, other):
        if not isinstance(other, Money):
            return NotImplemented
        if other.currency != self.currency:
            raise ValueError("cannot add different currencies")
        return Money(self.cents + other.cents, self.currency)

    def __lt__(self, other):
        if not isinstance(other, Money):
            return NotImplemented
        return self.cents < other.cents

total = Money(150) + Money(275)
print(total)                                   # Money(425, 'USD')
print(sorted([Money(30), Money(10), Money(20)]))  # [Money(10, 'USD'), Money(20, 'USD'), Money(30, 'USD')]
print(sum([Money(1), Money(2)], Money(0)))     # Money(3, 'USD')
Mantén los métodos coherentesLos objetos que son iguales deben tener hashes iguales, el orden debe concordar con la igualdad y __repr__ debe mostrar todo lo que mira __eq__. No des a + efectos secundarios sorprendentes: debe devolver un valor nuevo y dejar intactos ambos operandos, como los números. Las pruebas del lab comprueban estos puntos: originales sin cambios, monedas distintas rechazadas y tipos sin relación que dan NotImplemented.
  • __repr__ devuelve una cadena (como Money(1999, 'USD')); no imprime.
  • __eq__ compara campos y devuelve NotImplemented para tipos ajenos; añade __hash__ para conservar el hash.
  • __add__ devuelve un objeto nuevo; __lt__ basta para sorted, min y max.

A continuación: dataclasses, que escriben __init__, __repr__ y __eq__ por ti.

Lab: qué se califica

  • Mostrar un objeto Money con claridad con __repr__25 pts
  • Decir cuándo dos importes son iguales con __eq__25 pts
  • Sumar dos importes con __add__25 pts
  • Hacer ordenables los importes con __lt__25 pts
Explorador · lab-27-1
▾ lab-27-1
…
bash · en el navegador
learner@quantcraft:~/lab-27-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

Todo lo que hay en lab-27-1 vuelve a los archivos iniciales y se limpia el terminal. Tu solución actual se perderá: no se puede deshacer.

Se restablecerá
  • main.py → código inicial
  • Historial del terminal y salida de pruebas
  • Cambios sin enviar
Se conservará
  • Mejor puntuación del lab
  • Tu XP y tu racha
  • Progreso de la lección y notas

Inicia sesión para ejecutar tu código.

Todas las clases se pueden leer gratis. Crea una cuenta o inicia sesión para ejecutar código, lanzar las pruebas y enviar este lab.

  • IDE en el navegador con terminal bash — sin instalar nada
  • Corrección instantánea, XP y tu lugar en la ruta
Crear una cuentaIniciar sesión
O
Continuar con GitHub