¿Cómo obtener el índice de un entero de una lista si la lista contiene un valor booleano?

Estoy empezando con Python.

¿Cómo obtener el índice del número entero 1 de una lista si la lista contiene un objeto True booleano antes del 1 ?

 >>> lst = [True, False, 1, 3] >>> lst.index(1) 0 >>> lst.index(True) 0 >>> lst.index(0) 1 

Creo que Python considera 0 como False y 1 como True en el argumento del método de index . ¿Cómo puedo obtener el índice del número entero 1 (es decir, 2 )?

Además, ¿cuál es el razonamiento o la lógica detrás de tratar el objeto booleano de esta manera en la lista? A partir de las soluciones, puedo ver que no es tan sencillo.

La documentación dice que

Las listas son secuencias mutables, que generalmente se utilizan para almacenar colecciones de elementos homogéneos (donde el grado de similitud variará según la aplicación).

No debe almacenar datos heterogéneos en las listas. La implementación de list.index solo realiza la comparación utilizando Py_EQ ( == operador). En su caso, esa comparación devuelve un valor True porque True y False tienen valores de los enteros 1 y 0, respectivamente ( la clase bool es una subclase de int después de todo).

Sin embargo, podría usar la expresión del generador y la next función incorporada (para obtener el primer valor del generador) de la siguiente manera:

 In [4]: next(i for i, x in enumerate(lst) if not isinstance(x, bool) and x == 1) Out[4]: 2 

Aquí verificamos si x es una instancia de bool antes de comparar x con 1.

Tenga en cuenta que a next puede generar StopIteration , en ese caso, se puede desear (re) elevar ValueError (para imitar el comportamiento de list.index ).

Envolviendo todo esto en una función:

 def index_same_type(it, val): gen = (i for i, x in enumerate(it) if type(x) is type(val) and x == val) try: return next(gen) except StopIteration: raise ValueError('{!r} is not in iterable'.format(val)) from None 

Algunos ejemplos:

 In [34]: index_same_type(lst, 1) Out[34]: 2 In [35]: index_same_type(lst, True) Out[35]: 0 In [37]: index_same_type(lst, 42) ValueError: 42 is not in iterable 

Los booleanos son enteros en Python, y es por eso que puedes usarlos como cualquier entero:

 >>> 1 + True 2 >>> [1][False] 1 

[Esto no significa que debas :)]

Esto se debe al hecho de que bool es una subclase de int , y casi siempre un booleano se comportará como 0 o 1 (excepto cuando se convierte en cadena, en su lugar obtendrá "False" y "True" ).

Aquí hay una idea más de cómo puede lograr lo que quiere (sin embargo, intente reconsiderar su lógica teniendo en cuenta la información anterior):

 >>> class force_int(int): ... def __eq__(self, other): ... return int(self) == other and not isinstance(other, bool) ... >>> force_int(1) == True False >>> lst.index(force_int(1)) 2 

Este código redefine el método de int , que se utiliza para comparar elementos en el método de index , para ignorar los booleanos.

Aquí hay una solución ingenua de una sola línea que usa map y zip :

 >>> zip(map(type, lst), lst).index((int, 1)) 2 

Aquí asignamos el tipo de cada elemento y creamos una nueva lista comprimiendo los tipos con los elementos y solicitando el índice de (type, value) .

Y aquí hay una solución iterativa genérica usando la misma técnica:

 >>> from itertools import imap, izip >>> def index(xs, x): ... it = (i for i, (t, e) in enumerate(izip(imap(type, xs), xs)) if (t, e) == x) ... try: ... return next(it) ... except StopIteration: ... raise ValueError(x) ... >>> index(lst, (int, 1)) 2 

Aquí básicamente hacemos lo mismo pero iterativamente para no costarnos mucho en términos de eficiencia de memoria / espacio. Somos un iterador de la misma expresión desde arriba, pero en su lugar usamos imap e izip y creamos una función de índice personalizada que devuelve el siguiente valor del iterador o ValueError un ValueError si no hay coincidencia.

Intenta esto.

 for i, j in enumerate([True, False, 1, 3]): if not isinstance(j, bool) and j == 1: print i 

Salida:

 2