NaN se maneja perfectamente cuando verifico su presencia en una lista o un conjunto. Pero no entiendo cómo. [ACTUALIZACIÓN: no, no lo es; se informa como presente si se encuentra la instancia idéntica de NaN; si se encuentran únicos casos no idénticos de NaN, se ha informado como ausente.]Comprobación de presencia de NaN en un contenedor
pensé presencia en una lista es probado por la igualdad, por lo que espera NaN a no ser encontrado desde NaN! = NaN.
hash (NaN) y hash (0) son 0. ¿En qué se diferencian los diccionarios y los juegos de NaN y 0?
¿Es seguro verificar la presencia de NaN en un contenedor arbitrario usando el operador
in
? ¿O depende de la implementación?
Mi pregunta es acerca de Python 3.2.1; pero si hay algún cambio existente/planificado en futuras versiones, me gustaría saberlo también.
NaN = float('nan')
print(NaN != NaN) # True
print(NaN == NaN) # False
list_ = (1, 2, NaN)
print(NaN in list_) # True; works fine but how?
set_ = {1, 2, NaN}
print(NaN in set_) # True; hash(NaN) is some fixed integer, so no surprise here
print(hash(0)) # 0
print(hash(NaN)) # 0
set_ = {1, 2, 0}
print(NaN in set_) # False; works fine, but how?
Tenga en cuenta que si añado una instancia de una clase definida por el usuario a un list
, y a continuación, comprobar para la contención, se llama al método de la instancia __eq__
(si está definida) - por lo menos en CPython. Es por eso que asumí que la contención list
se prueba usando el operador ==
.
EDIT:
respuesta de Per romana, parecería que __contains__
para list
, tuple
, set
, dict
se comporta de una manera muy extraña:
def __contains__(self, x):
for element in self:
if x is element:
return True
if x == element:
return True
return False
digo 'extraño' porque yo no' T verlo explicado en la documentación (tal vez me lo perdí), y creo que esto es algo que no debería dejarse como una opción de implementación.
Por supuesto, un objeto NaN puede no ser idéntico (en el sentido de id
) a otro objeto NaN. (Esto no es realmente sorprendente, Python no garantiza esa identidad. De hecho, nunca vi a CPython compartir una instancia de NaN creada en diferentes lugares, aunque comparte una instancia de un número pequeño o una cadena corta.) Esto significa que las pruebas de presencia de NaN en un contenedor integrado no están definidas.
Esto es muy peligroso y muy sutil. Alguien podría ejecutar el mismo código que mostré anteriormente y concluir de manera incorrecta que es seguro probar la membresía de NaN usando in
.
No creo que haya una solución perfecta a este problema. Un enfoque muy seguro es garantizar que los NaN nunca se agreguen a los contenedores incorporados. (Es un dolor comprobar que todo el código ...)
Otra alternativa es tener cuidado con los casos en que in
podría tener NaN en el lado izquierdo, y en tales casos, probar la membresía NaN por separado, utilizando math.isnan()
. Además, otras operaciones (p. Ej., Establecer intersección) también deben evitarse o reescribirse.
Bottonline: para estar en el lado seguro use: any (math.isnan (element) for element in list_) – jsbueno
@jsbueno: Sip ... Pero eso no ayuda con el problema de intersección establecida; ni maneja el caso de 'para x en cont1: si x en cont2 hace algo' ... Diría que la conclusión es" ten mucho miedo, y solo espero que no pases por alto algo " – max
Ganó ' t ayuda, y tiene que aceptar que no hay una solución fácil. Puede usar el ciclo superior para convertir cualquier NaN a cadenas que digan "NaN"; se compararán de forma no equitativa. – jsbueno