tablas - conjunto de Python contiene vs. lista contiene
read text pandas python (2)
Estoy usando Python 2.7
considere el siguiente fragmento de código (el ejemplo es inventado):
import datetime
class ScheduleData:
def __init__(self, date):
self.date = date
def __eq__(self, other):
try:
return self.date == other.date
except AttributeError as e:
return self.date == other
def __hash__(self):
return hash(self.date)
schedule_set = set()
schedule_set.add(ScheduleData(datetime.date(2010, 8, 7)))
schedule_set.add(ScheduleData(datetime.date(2010, 8, 8)))
schedule_set.add(ScheduleData(datetime.date(2010, 8, 9)))
print (datetime.date(2010, 8, 8) in schedule_set)
schedule_list = list(schedule_set)
print (datetime.date(2010, 8, 8) in schedule_list)
el resultado de esto es inesperado (para mí, al menos):
[08:02 PM toolscripts]$ python test.py
True
False
en el primer caso, la fecha dada se encuentra en el schedule_set
ya que he anulado las funciones __hash__
y __eq__
.
desde mi punto de vista, el operador in
comprobará el hash y la igualdad para los conjuntos, pero para las listas simplemente repetirá los elementos de la lista y comprobará la igualdad.
¿Entonces, Que esta pasando aquí? ¿Por qué falla mi segunda prueba para entrar in
la lista schedule_list
?
¿Tengo que anular alguna otra función para las listas?
@RyanHaining es correcto. Para una solución realmente extraña, agregue este método a su clase:
def timetuple(self):
return None
Entonces su programa imprimirá True
dos veces. Las razones de esto están involucradas, teniendo que ver con una desafortunada historia de comparaciones en Python 2 demasiado flojo. La solución timetuple()
se explica principalmente en esta parte de los documentos:
Nota: Para evitar que la comparación vuelva a caer en el esquema predeterminado de comparación de direcciones de objetos, la comparación de fecha y hora normalmente genera TypeError si la otra compañía no es también un objeto de fecha y hora. Sin embargo, NotImplemented se devuelve en su lugar si la otra comparand tiene un atributo timetuple (). Este gancho brinda a otros tipos de objetos de fecha la oportunidad de implementar una comparación de tipo mixto. De lo contrario, cuando se compara un objeto datetime con un objeto de un tipo diferente, TypeError se genera a menos que la comparación sea == o! =. Los últimos casos devuelven falso o verdadero, respectivamente.
datetime
fue uno de los primeros tipos agregados a Python que intentó ofrecer un comportamiento de comparación menos sorprendente. Pero no podría convertirse en "realmente limpio" hasta Python 3.
El problema es que la comparación invoca una función __eq__
opuesta a lo que estás buscando. El método __eq__
definido funciona cuando tiene un ScheduleData() == datetime.date()
pero el operador in
está realizando la comparación en el orden opuesto, datetime.date() == ScheduleData()
que no invoca su __eq__
definido. Solo la clase que actúa como el lado izquierdo tendrá su __eq__
llamada.
La razón por la cual este problema ocurre en python 2 y no 3 tiene que ver con la definición de datetime.date.__eq__
en la biblioteca std. Tomemos por ejemplo las siguientes dos clases:
class A(object):
def __eq__(self, other):
print (''A.__eq__'')
return False
class B(object):
def __eq__(self, other):
print (''B.__eq__'')
items = [A()]
B() in items
Al ejecutar este código, se imprime B.__eq__
en Python 2 y Python 3. El objeto B
se usa como lhs, al igual que su objeto datetime.date
se usa en Python 2. Sin embargo, si B.__eq__
para que se parezca a Python 3 definición de datetime.date.__eq__
:
class B(object):
def __eq__(self, other):
print (''First B.__eq__'')
if isinstance(self, other.__class__):
print (''B.__eq__'')
return NotImplemented
Entonces:
First B.__eq__
A.__eq__
se imprime en Python 2 y 3. La devolución de NotImplemented
causa la comprobación con los argumentos invertidos.
Usar timetuple
en tu clase solucionará este problema, como dijo @TimPeters (peculiaridad interesante que desconocía), aunque parece que no necesita ser una función
class ScheduleData:
timetuple = None
es todo lo que necesitarías además de lo que ya tienes.