2011-12-19 15 views
14
>>> False in [0] 
True 
>>> type(False) == type(0) 
False 

La razón me encontré con este:Python "in" no verifica el tipo?

Para mi unidad de pruebas que crea listas de valores de ejemplo válidos y no válidos para cada uno de mis tipos. (con 'mis tipos' quiero decir, no son 100% iguales a los tipos de python) Así que quiero iterar la lista de todos los valores y esperar que pasen si están en mis valores válidos, y por otro lado, fallar si no lo son que no funciona tan bien ahora:

>>> valid_values = [-1, 0, 1, 2, 3] 
>>> invalid_values = [True, False, "foo"] 
>>> for value in valid_values + invalid_values: 
...  if value in valid_values: 
...   print 'valid value:', value 
... 
valid value: -1 
valid value: 0 
valid value: 1 
valid value: 2 
valid value: 3 
valid value: True 
valid value: False 

Por supuesto estoy de acuerdo con los dos últimos valores válidos ''.

¿Esto significa que realmente tengo que iterar a través de mis valid_values ​​y comparar el tipo?

+0

+1 Hmm, nunca pensé que el 'en' de python no buscaba el tipo. Muy interesante . . . – OnesimusUnbound

+0

@BenJames, hmm, me pregunto cómo sería romper el pato escribiendo en Python? – OnesimusUnbound

Respuesta

4

Como otros han escrito, el "en" código no hace lo quieres que haga Necesitarás algo más.

Si realmente desea una verificación de tipos (en la que el cheque es de exactamente el mismo tipo), entonces puede incluir el tipo de la lista:

>>> valid_values = [(int, i) for i in [-1, 0, 1, 2, 3]] 
>>> invalid_values = [True, False, "foo"] 
>>> for value in [v[1] for v in valid_values] + invalid_values: 
... if (type(value), value) in valid_values: 
...  print value, "is valid" 
... else: 
...  print value, "is invalid" 
... 
-1 is valid 
0 is valid 
1 is valid 
2 is valid 
3 is valid 
True is invalid 
False is invalid 
foo is invalid 
>>> 

Manejo subtipos es un poco más difícil, y dependerá en lo que quieres hacer

+0

Utilicé su solución para evitar el ciclo adicional. Pero lo cambié a: valid_values ​​= [(tipo (v), v) para v en [-1, 0, 1, 2, 3]] –

15

El problema no es la comprobación de tipos faltantes, sino porque en Python bool es una subclase de int. Prueba esto:

>>> False == 0 
True 
>>> isinstance(False, int) 
True 
+0

No me quejo de False == 0, pero solo sobre el hecho de que "in" no verificará el tipo. –

+6

'in' devuelve verdadero si un elemento en la secuencia es' igual' al objeto solicitado. Entonces su problema no es el operador 'in', sino el operador' == '. – Constantinius

+0

Solo me gustaría tener un cheque de identidad allí. ¿Hay alguna manera de hacer esto sin usar un bucle? –

6

De acuerdo con la documentation, __contains__ se realiza mediante la iteración en la extracción y verificación de elementos por ==. Por lo tanto, el problema real es causado por el hecho de que False == 0 es True.

+0

Para el pedante ... comprueba primero un '' __contains __ (self, thing) '' método, * luego * vuelve a iterar sobre el objeto. Para una verdadera '' list'', hay '' __contains__'', por lo tanto, la reserva. –

+0

@GreggLind, por supuesto, tiene razón.Sin embargo, no pude encontrar una mejor definición de "en". Para ajustarse al principio de menor sorpresa, un método sobrecargado '__contains__' debería hacer algo similar de todos modos. –

+1

He tenido este mordisco cuando la determinación de la contención agota un generador y/o se ejecuta para siempre. Evitable escribiendo un * más inteligente * '' __contains__''. (piense en cosas como '' itertools.cycle'') –

3

Desde True == 1 y False == 0 Es difícil diferenciar entre los dos.

Un enfoque posible, pero feo (que tampoco se garantiza que funcione en todas las implementaciones de Python, pero debe estar bien en CPython):

>>> for value in valid_values + invalid_values: 
... if value in valid_values and not any(v is value for v in invalid_values): 
...  print ('valid value:', value) 
... 
valid value: -1 
valid value: 0 
valid value: 1 
valid value: 2 
valid value: 3 
+0

Me hubiera gustado evitar otro ciclo. Dado que este control se ejecutará con bastante frecuencia durante la mayoría de mis pruebas. –

Cuestiones relacionadas