Probar si una variable es una lista o tupla


234

En python, ¿cuál es la mejor manera de probar si una variable contiene una lista o una tupla? (es decir, una colección)

¿Es isinstance()tan malvado como se sugiere aquí? http://www.canonical.org/~kragen/isinstance/

Actualización: la razón más común por la que quiero distinguir una lista de una cadena es cuando tengo un árbol anidado indefinidamente / estructura de datos de listas de listas de listas de cadenas, etc., que estoy explorando con un algoritmo recursivo y necesito saber cuándo he golpeado los nodos "hoja".


72
En términos generales, descartar la verificación de tipos como malvada es un poco fácil. Es parte del lenguaje. Si es tan malo, alguien debería escribir un PEP para eliminarlo.
Adam Crossland

44
@Adam Crossland: "Es parte del lenguaje". Al igual que la división por cero. Es evitable En este caso, sin información adicional, probablemente sea completamente innecesario. La mayoría de las verificaciones de tipo en Python son innecesarias. Como no todo es innecesario, es necesario que exista algún tipo de verificación. Pero eso no significa que sea útil, valioso o incluso una buena idea.
S.Lott

11
Entonces estás diciendo que se necesita algún tipo de verificación, pero a pesar de eso, es inútil, inútil y una mala idea. Lo siento, eso simplemente no tiene sentido.
Glenn Maynard

18
El "XXX es malvado" está mal concebido, es una forma abreviada y engañosa de "la forma en que estás pidiendo hacer XXX sugiere que no entiendes cuándo debería usarse, y casi seguro que quieres algo más". Ese es probablemente el caso aquí.
Glenn Maynard

2
En general no lo descarté como malvado. Escribí un breve ensayo sobre cuándo es malo y cuándo es justificable. Ese ensayo puede ser muchas cosas: correcto, incorrecto, claro, vago, agradable, aburrido, pero una cosa que no es es un amplio rechazo de la técnica.
Kragen Javier Sitaker

Respuestas:


101

Siga adelante y utilícelo isinstancesi lo necesita. Es algo malvado, ya que excluye secuencias personalizadas, iteradores y otras cosas que realmente pueda necesitar. Sin embargo, a veces debe comportarse de manera diferente si alguien, por ejemplo, pasa una cadena. Mi preferencia sería verificar explícitamente stro de esta unicodemanera:

import types
isinstance(var, types.StringTypes)

NB No te confundas types.StringTypecon types.StringTypes. Este último incorpora stry unicodeobjetos.

El typesmódulo es considerado por muchos como obsoleta en favor de sólo la comprobación directamente contra el tipo del objeto, así que si usted prefiere no utilizar el anterior, alternativamente, puede comprobar de forma explícita en contra stry unicode, de esta manera:

isinstance(var, (str, unicode)):

Editar:

Mejor aún es:

isinstance(var, basestring)

Finalizar edición

Después de cualquiera de estos, puede volver a comportarse como si estuviera obteniendo una secuencia normal, dejando que las no secuencias generen las excepciones apropiadas.

Vea que lo "malo" de la verificación de tipos no es que desee comportarse de manera diferente para un determinado tipo de objeto, es que restringe artificialmente su función de hacer lo correcto con tipos de objetos inesperados que de otro modo harían lo correcto. Si tiene una copia de seguridad final que no está marcada, elimine esta restricción. Cabe señalar que demasiada verificación de tipo es un olor a código que indica que es posible que desee refactorizar, pero eso no significa necesariamente que deba evitarlo desde el principio.


2
El módulo de tipos es un poco un artefacto histórico. Como se menciona en docs.python.org/dev/library/types.html#module-types si realmente debe verificar el strtipo, simplemente debe usarlo directamente, en lugar de usar, types.StringTypeque es solo un alias para él. Pero no creo que esta respuesta responda a la pregunta formulada, porque se trataba de "una colección". A menos que esté utilizando una python lo suficientemente nueva como para tener el abcmódulo que no es algo que pueda usar isinstancepara verificar, e incluso entonces recomendaría evitar la verificación si es posible.
mzz

1
assert isinstance(u'abc', str) == False. Estoy de acuerdo en que es mejor verificar el tipo directamente, en lugar de usar el typesmódulo, pero types.StringTypeshace algo que strno: devuelve True para stry unicodeobjetos. Editaré mi respuesta para ofrecer una doble verificación como alternativa.
jcdyer

1
Me doy cuenta de que no respondí la pregunta de buscar colecciones directamente, pero la pregunta real fue "¿Es isinstancemalo?" Y di un contraejemplo en el que (1) es un uso no malvado isinstance, porque tener un retroceso significa que no rompe el patito, y (2) es una buena solución para una motivación muy común que las personas tienen para querer verificar si algo es un listo tuple(es decir, desambiguarlos de las cadenas).
jcdyer

Estoy de acuerdo, con la advertencia de que a menudo es útil que los tipos personalizados también se comporten como cadenas. Pero el OO de Python solo va tan lejos ...
Kragen Javier Sitaker

¿Hace class Foo(str): passlo que quieres?
jcdyer

568
if type(x) is list:
    print 'a list'
elif type(x) is tuple:
    print 'a tuple'
else:
    print 'neither a tuple or a list'

1
No parece funcionar: escriba ([]) ==> lista; type ([]) is list ===> False
sten

3
En Python 2.7.5: type([]) is listregresaTrue
David Geiger

54
type(x) in [list,tuple]Es más corto.
Alex Holcombe

si x y tipo (x) es la lista: para evitar la falta de coincidencia []
Kenichi Shibata

Tuve que desplazarme mucho hacia abajo. : D
Rithwik

38

No hay nada de malo en usar isinstancesiempre que no sea redundante. Si una variable solo debe ser una lista / tupla, documente la interfaz y simplemente úsela como tal. De lo contrario, un cheque es perfectamente razonable:

if isinstance(a, collections.Iterable):
    # use as a container
else:
    # not a container!

Este tipo de verificación tiene algunos buenos casos de uso, como con los métodos estándar de cadena comienza con / termina con (aunque para ser precisos, estos se implementan en C en CPython usando una verificación explícita para ver si es una tupla: hay más de una forma para resolver este problema, como se menciona en el artículo al que se vincula).

Una verificación explícita a menudo es mejor que intentar usar el objeto como un contenedor y manejar la excepción, que puede causar todo tipo de problemas con el código que se ejecuta parcial o innecesariamente.


15
Esta es una buena manera de verificar si una variable es iterable. Sin embargo, probablemente no funcionará a los fines de esta pregunta. Tenga en cuenta que una cadena también es iterable y probablemente crearía un falso positivo.
Corey O.

Un setobjeto también es iterable, lo que significa que si bien seguramente puede extraer elementos de él, pero no garantiza un cierto orden, lo cual es algo muy peligroso para ciertos algoritmos. En los casos en que el orden de los elementos sí importa, ¡un algoritmo que use este fragmento podría generar resultados diferentes en ejecuciones diferentes!
koo


12

¿Qué tal hasattr(a, "__iter__"):?

Indica si el objeto devuelto puede iterarse como un generador. Por defecto, las tuplas y las listas pueden, pero no los tipos de cadena.


Encontré esto realmente útil.
Java

8
También resulta verdadero para cadenas (al menos en Python 3).
SzieberthAdam

2
Esta es una respuesta incorrecta. Dado que el tipo 'str' tiene el método ' iter ' también. @SzieberthAdam tenía razón. El tipo 'conjunto' también es iterable, pero no es ordenable.
PADYMKO

También los dictos tienen __iter__.
Thet

Si continúa, cualquier tipo personalizado puede tener __iter__por alguna razón ...
Alexander Irbis

10

En Python 2.8 type(list) is listrendimientos false
que sugeriría comparando el tipo en esta horrible manera:

if type(a) == type([]) :
  print "variable a is a list"

(bueno, al menos en mi sistema, usando anaconda en Mac OS X Yosemite)


1
¿El tipo (a) es la lista también se evalúa como falso?
Dmitriy Sintsov


Hola, tengo curiosidad: ¿por qué consideras que tu ejemplo es "horrible"?
Seth Connell

type(list) is listvuelve Falseporque type(list)es type, no list. type(list()) is listo con cualquier otra instancia de una lista volverá True.
Michael Greene

8

Python utiliza "Mecanografía pato", es decir, si una variable se mueve como un pato, debe ser un pato. En su caso, es probable que desee que sea iterable o que desee acceder al elemento en un índice determinado. Simplemente debe hacer esto: es decir, usar el objeto dentro for var:o var[idx]dentro de un trybloque, y si obtiene una excepción, no fue un pato ...


77
El problema con esto es si varse producirá una iteración de cadena con resultados probablemente inesperados.
Brian M. Hunt

A pesar del hecho declarado por Brian M. Hunt, esta es una solución bastante pitónica, en términos de pedir perdón en lugar de permiso.
Géza Török

6
>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True

3

Si solo necesita saber si puede usar la foo[123]notación con la variable, puede verificar la existencia de un __getitem__atributo (que es lo que Python llama cuando accede por índice) conhasattr(foo, '__getitem__')


2

Tiene que ser una prueba más compleja si realmente desea manejar casi cualquier cosa como argumento de función.

type(a) != type('') and hasattr(a, "__iter__")

Aunque, por lo general, es suficiente explicar que una función espera iterable y luego verificar solo type(a) != type('').

También puede suceder que para una cadena tengas una ruta de procesamiento simple o que seas agradable y hagas una división, etc., por lo que no quieres gritar a las cadenas y si alguien te envía algo extraño, solo déjalo tener una excepción.


2

Otra forma fácil de averiguar si una variable es lista o tupla o, en general, verificar el tipo de variable sería:

    def islist(obj):

        if ("list" in str(type(obj)) ): return True

        else : return False

1

En principio, estoy de acuerdo con Ignacio, arriba, pero también puede usar el tipo para verificar si algo es una tupla o una lista.

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.