Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

187
Vistas
Aplicación de órdenes __eq__ en Python

Una pregunta un poco larga para explicar suficientemente el trasfondo...

Suponiendo que hay una class A incorporada:

 class A: def __init__(self, a=None): self.a = a def __eq__(self, other): return self.a == other.a

Se espera comparar de esta manera:

 a1, a2 = A(1), A(2) a1 == a2 # False

Por alguna razón, el equipo introdujo un envoltorio encima ( el código de ejemplo en realidad no envuelve A para simplificar la complejidad del código).

 class WrapperA: def __init__(self, a=None): self.pa = a def __eq__(self, other): return self.pa == other.pa

Nuevamente, se espera comparar de esta manera:

 wa1, wa2 = WrapperA(1), WrapperA(2) wa1 == wa2 # False

Aunque se espera que use A o WrapperA , el problema es que algunas bases de código contienen ambos usos, por lo que la siguiente comparación falló:

 a, wa = A(), WrapperA() wa == a # AttributeError a == wa # AttributeError

Una solución conocida es modificar __eq__ :

Para wa == a :

 class WrapperA: def __init__(self, a=None): self.pa = a def __eq__(self, other): if isinstance(other, A): return self.pa == other.a return self.pa == other.pa

Para a == wa :

 class A: def __init__(self, a=None): self.a = a def __eq__(self, other): if isinstance(other, WrapperA): return self.a == other.pa return self.a == other.a

Se espera modificar WrapperA. Para A, dado que es una cosa incorporada, dos soluciones son:

  1. Use setattr para extender A para admitir WrapperA.
 setattr(A, '__eq__', eq_that_supports_WrapperA)
  1. Obligue al desarrollador a comparar solo wa == a (y luego no se preocupe por a == wa ).

La primera opción es obviamente fea con la implementación duplicada, y la segunda le da al desarrollador una "sorpresa" innecesaria. Así que mi pregunta es, ¿hay alguna forma elegante de reemplazar cualquier uso de a == wa to wa == a por la implementación de Python internamente?

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Realmente no me gusta todo esto, ya que creo que envolver una función integrada y usar diferentes nombres de atributos conducirá a cosas inesperadas, pero de todos modos, esto funcionará para ti.

 import inspect class A: def __init__(self, a=None): self.a = a def __eq__(self, other): return self.a == other.a class WrapperA: def __init__(self, a=None): self.pa = a def __eq__(self, other): if isinstance(other, A): return self.pa == other.a return self.pa == other.pa def __getattribute__(self, item): # Figure out who tried to get the attribute # If the item requested was 'a', check if A's __eq__ method called us, # in that case return pa instead caller = inspect.stack()[1] if item == 'a' and getattr(caller, 'function') == '__eq__' and isinstance(caller.frame.f_locals.get('self'), A): return super(WrapperA, self).__getattribute__('pa') return super(WrapperA, self).__getattribute__(item) a = A(5) wrap_a = WrapperA(5) print(a == wrap_a) print(wrap_a == a) wrap_a.pa = 7 print(a == wrap_a) print(wrap_a == a) print(f'{wrap_a.pa=}')

Producción:

 True True False False wrap_a.pa=7
over 4 years ago · Santiago Trujillo Denunciar

0

Citando el comentario de MisterMiyagi bajo la pregunta:

Tenga en cuenta que generalmente se espera que == funcione en todos los tipos. A.__eq__ requerir que otro sea un A es en realidad un error que debe corregirse. Como mínimo, debería devolver NotImplemented cuando no puede tomar una decisión.

Esto es importante, no solo una cuestión de estilo. De hecho, segúnla documentación :

Cuando un método binario (o in situ) devuelve NotImplemented el intérprete intentará la operación reflejada en el otro tipo.

Por lo tanto, si solo aplica el comentario de MisterMiyagi y corrige la lógica de __eq__ , verá que su código ya funciona bien:

 class A: def __init__(self, a=None): self.a = a def __eq__(self, other): if isinstance(other, A): return self.a == other.a return NotImplemented class WrapperA: def __init__(self, a=None): self.pa = a def __eq__(self, other): if isinstance(other, A): return self.pa == other.a elif isinstance(other, WrapperA): return self.pa == other.pa return NotImplemented # Trying it a = A(5) wrap_a = WrapperA(5) print(a == wrap_a) print(wrap_a == a) wrap_a.pa = 7 print(a == wrap_a) print(wrap_a == a) print(f'{wrap_a.pa=}')

Rendimientos:

 True True False False wrap_a.pa=7

Bajo el capó, a == wrap_a llama a A.__eq__ primero, que devuelve NotImplemented . Python luego prueba automáticamente WrapperA.__eq__ en su lugar.

over 4 years ago · Santiago Trujillo Denunciar

0

Similar a la respuesta de Ron Serruya:

Esto usa __getattr__ en lugar de __getattribute__ , donde el primero solo se llama si el segundo genera un AttributeError o lo llama explícitamente (ref) . Esto significa que si el envoltorio no implementa __eq__ y la igualdad solo debe realizarse en la estructura de datos subyacente (almacenada en objetos de clase A ), un ejemplo de trabajo es el siguiente:

 class A(object): def __init__(self, internal_data=None): self._internal_data = internal_data def __eq__(self, other): return self._internal_data == other._internal_data class WrapperA(object): def __init__(self, a_object: A): self._a = a_object def __getattr__(self, attribute): if attribute != '_a': # This is neccessary to prevent recursive calls return getattr(self._a, attribute) a1 = A(internal_data=1) a2 = A(internal_data=2) wa1 = WrapperA(a1) wa2 = WrapperA(a2) print( a1 == a1, a1 == a2, wa1 == wa1, a1 == wa1, a2 == wa2, wa1 == a1) >>> True False True True True True
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda