variable type islist check array python list types assert

type - python isinstance



¿Cómo verificar si un objeto es una lista o una tupla(pero no una cadena)? (17)

Esto es lo que normalmente hago para comprobar que la entrada es una list / tuple , pero no una str . Porque muchas veces me topé con errores en los que una función pasa un objeto str por error, y la función objetivo lo hace for x in lst suponiendo que lst es en realidad una list o tuple .

assert isinstance(lst, (list, tuple))

Mi pregunta es: ¿hay una mejor manera de lograr esto?


El objeto str no tiene un atributo __iter__

assert hasattr(x, ''__iter__'')

para que puedas hacer un cheque

import types if isinstance(lst, types.ListType) or isinstance(lst, types.TupleType): # Do something

y esto también generará un buen AssertionError para cualquier otro objeto no iterable.

Edición: como Tim menciona en los comentarios, esto solo funcionará en python 2.x, no 3.x


En forma de "pato escribiendo", ¿qué tal

try: lst = lst + () except TypeError: #it''s not a tuple

o

try: lst = lst + '''' except TypeError: #it''s not (base)string

respectivamente. Esto evita las cosas de introspección isinstance / hasattr .

También puede comprobar viceversa:

from typing import List def isit(value): return isinstance(value, List) isit([1, 2, 3]) # True isit("test") # False isit({"Hello": "Mars"}) # False isit((1, 2)) # False

Todas las variantes no cambian realmente el contenido de la variable, pero implican una reasignación. No estoy seguro de que esto sea indeseable en algunas circunstancias.

Curiosamente, con la asignación "en el lugar" += no TypeError generaría en cualquier caso si lst es una lista (no una tupla ). Es por eso que la tarea se realiza de esta manera. Tal vez alguien pueda arrojar luz sobre por qué es eso.


En términos generales, el hecho de que una función que itera sobre un objeto funcione en cadenas así como en tuplas y listas es más una característica que un error. Ciertamente, puede usar isinstance o duck typing para verificar un argumento, pero ¿por qué debería hacerlo?

Eso suena como una pregunta retórica, pero no lo es. La respuesta a "¿por qué debería verificar el tipo de argumento?" Probablemente va a sugerir una solución al problema real, no el problema percibido. ¿Por qué es un error cuando se pasa una cadena a la función? Además: si se trata de un error cuando se pasa una cadena a esta función, ¿es también un error si se le pasa alguna otra iterable que no sea de lista / tupla? ¿Por qué o por qué no?

Creo que la respuesta más común a la pregunta es que los desarrolladores que escriben f("abc") esperan que la función se comporte como si hubieran escrito f(["abc"]) . Probablemente hay circunstancias en las que tiene más sentido proteger a los desarrolladores de sí mismos que respaldar el caso de uso de la iteración a través de los caracteres en una cadena. Pero primero pensaría mucho en ello.


Encuentro una función llamada is_sequence en tensorflow .

def assertIsIterable(self, item): #add types here you don''t want to mistake as iterables if isinstance(item, basestring): raise AssertionError("type %s is not iterable" % type(item)) #Fake an iteration. try: for x in item: break; except TypeError: raise AssertionError("type %s is not iterable" % type(item))

Y he comprobado que satisface tus necesidades.


Esto no pretende responder directamente al OP, pero quería compartir algunas ideas relacionadas.

Estaba muy interesado en la respuesta de @steveha anterior, que parecía dar un ejemplo donde la tipificación de pato parece romperse. Pensándolo bien, sin embargo, su ejemplo sugiere que es difícil ajustarse a la tipificación de pato, pero no sugiere que str merezca ningún manejo especial.

Después de todo, un tipo no str (por ejemplo, un tipo definido por el usuario que mantiene algunas estructuras recursivas complicadas) puede causar que la función srepr srepr provoque una recursión infinita. Si bien esto es bastante improbable, no podemos ignorar esta posibilidad. Por lo tanto, en lugar de la srepr especial str en srepr , deberíamos aclarar lo que queremos que srepr haga cuando se produce una recursión infinita.

Puede parecer que un enfoque razonable es simplemente romper la recursión en srepr la list(arg) == [arg] momentos list(arg) == [arg] . Esto, de hecho, resolvería completamente el problema con str , sin ninguna isinstance .

Sin embargo, una estructura recursiva realmente complicada puede causar un bucle infinito donde la list(arg) == [arg] nunca sucede. Por lo tanto, mientras que la verificación anterior es útil, no es suficiente. Necesitamos algo como un límite duro en la profundidad de la recursión.

Mi punto es que si planea manejar tipos de argumentos arbitrarios, el manejo de str mediante la tipificación de pato es mucho más fácil que manejar los tipos más generales que puede (teóricamente) encontrar. Entonces, si sientes la necesidad de excluir instancias de str , deberías exigir que el argumento sea una instancia de uno de los pocos tipos que especificas explícitamente.


Hago esto en mis testcases.

>>> console_routers = ''x'' >>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)]) False >>> >>> console_routers = (''x'',) >>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)]) True >>> console_routers = list(''x'',) >>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)]) True

No probado en los generadores, creo que queda en el próximo ''rendimiento'' si se pasa en un generador, lo que puede arruinar las cosas río abajo. Pero, de nuevo, esto es un ''test de unidad''


Intente esto para mejorar la legibilidad y las mejores prácticas:

Python2

import typing if isinstance(lst, typing.List) or isinstance(lst, typing.Tuple): # Do something

Python3

def is_sequence(seq): """Returns a true if its input is a collections.Sequence (except strings). Args: seq: an input sequence. Returns: True if the sequence is a not a string and is a collections.Sequence. """ return (isinstance(seq, collections.Sequence) and not isinstance(seq, six.string_types))

Espero eso ayude.


Manera más simple ... usando any e isinstance

try: lst = lst + [] except TypeError: #it''s not a list


Para Python 2:

import collections if isinstance(obj, collections.Sequence) and not isinstance(obj, basestring): print "obj is a sequence (list, tuple, etc) but not a string or unicode"

Para Python 3:

def is_array(var): return isinstance(var, (list, tuple))

Modificado en la versión 3.3: Movió las clases base abstractas de colecciones al módulo collections.abc. Por compatibilidad con versiones anteriores, seguirán siendo visibles en este módulo hasta la versión 3.8, donde dejará de funcionar.


Python 3 tiene esto:

from typing import List, Tuple def isit(value): return isinstance(value, List) or isinstance(value, Tuple)

Entonces, para verificar si hay listas y tuplas, sería:

if type(lst) in (list, tuple): # Do stuff


Python con sabor PHP:

>>> hasattr('''', ''__iter__'') False


Recuerda que en Python queremos usar "tipografía de pato". Entonces, cualquier cosa que actúe como una lista puede ser tratada como una lista. Por lo tanto, no compruebe el tipo de lista, solo vea si actúa como una lista.

Pero las cuerdas también actúan como una lista, y a menudo eso no es lo que queremos. ¡Hay veces en que incluso es un problema! Por lo tanto, compruebe explícitamente si hay una cadena, pero luego use la escritura de pato.

Aquí hay una función que escribí por diversión. Es una versión especial de repr() que imprime cualquier secuencia entre paréntesis angulares (''<'', ''>'').

def srepr(arg): if isinstance(arg, basestring): # Python 3: isinstance(arg, str) return repr(arg) try: return ''<'' + ", ".join(srepr(x) for x in arg) + ''>'' except TypeError: # catch when for loop fails return repr(arg) # not a sequence so just return repr

Esto es limpio y elegante, en general. Pero, ¿qué es eso que isinstance() haciendo el cheque de isinstance() allí? Eso es una especie de hackeo. Pero es esencial.

Esta función se llama a sí misma recursivamente en cualquier cosa que actúe como una lista. Si no manejamos la cadena especialmente, entonces sería tratado como una lista, y dividiríamos un carácter a la vez. Pero entonces la llamada recursiva intentaría tratar a cada personaje como una lista, ¡y funcionaría! ¡Incluso una cadena de un carácter funciona como una lista! La función seguiría llamándose a sí misma de forma recursiva hasta que se desbordara la pila.

Las funciones como esta, que dependen de cada llamada recursiva que desglosa el trabajo a realizar, tienen que ser cadenas de casos especiales, porque no se puede dividir una cadena por debajo del nivel de una cadena de un solo carácter, e incluso una. -la cadena de caracteres actúa como una lista.

Nota: el try / except es la forma más limpia de expresar nuestras intenciones. Pero si este código fuera algo crítico en el tiempo, podríamos reemplazarlo con algún tipo de prueba para ver si arg es una secuencia. En lugar de probar el tipo, probablemente deberíamos probar los comportamientos. Si tiene un método .strip() , es una cadena, así que no lo consideres una secuencia; de lo contrario, si es indexable o iterable, es una secuencia:

def is_sequence(arg): return (not hasattr(arg, "strip") and hasattr(arg, "__getitem__") or hasattr(arg, "__iter__")) def srepr(arg): if is_sequence(arg): return ''<'' + ", ".join(srepr(x) for x in arg) + ''>'' return repr(arg)

EDITAR: originalmente escribí lo anterior con un cheque para __getslice__() pero noté que en la documentación del módulo de collections , el método interesante es __getitem__() ; Esto tiene sentido, así es como se indexa un objeto. Eso parece más fundamental que __getslice__() así que cambié lo anterior.


Si ya tienes pandas disponibles, puedes hacer esto:

for i in some_var: if type(i) == type(list()): #do something with a list elif type(i) == type(tuple()): #do something with a tuple elif type(i) == type(str()): #here''s your string

Esto es lo que hago para asegurar una lista.


Solo en python 2 (no python 3):

assert not isinstance(lst, basestring)

Es lo que realmente quieres, de lo contrario te perderás muchas cosas que actúan como listas, pero no son subclases de list o tuple .


Solo haz esto

variable = pd.Series(variable).tolist()


Tiendo a hacer esto (si realmente lo tuviera que hacer):

for i in some_var: if type(i) == type(list()): #do something with a list elif type(i) == type(tuple()): #do something with a tuple elif type(i) == type(str()): #here''s your string


H = "Hello" if type(H) is list or type(H) is tuple: ## Do Something. else ## Do Something.