while - with python español
Python: comprueba si un objeto es una secuencia (6)
¿Por qué estás haciendo esto? La forma normal aquí es requerir cierto tipo de cosas (una secuencia o un número o un objeto parecido a un archivo, etc.) y luego usarlo sin verificar nada. En Python, normalmente no usamos clases para llevar información semántica, sino que simplemente usamos los métodos definidos (esto se llama "tipa de pato"). También preferimos las API donde sabemos exactamente qué esperar; utilice argumentos de palabra clave, preprocesamiento o defina otra función si desea cambiar el funcionamiento de una función.
En Python, ¿hay alguna manera fácil de saber si algo no es una secuencia? Intenté hacer: if x is not sequence
pero a Python no le gustó
Creo que el siguiente fragmento de código hace lo que quieres:
def is_sequence(obj):
return hasattr(type(obj), ''__iter__'')
Dado que Python "cumple" la tipificación de pato, uno de los enfoques es verificar si un objeto tiene algún miembro (método).
Una secuencia tiene longitud, tiene una secuencia de elementos y admite cortar [ doc ]. Entonces, sería así:
def is_sequence(obj):
t = type(obj)
return hasattr(t, ''__len__'') and hasattr(t, ''__getitem__'')
# additionally: and hasattr(t, ''__setitem__'') and hasattr(t, ''__delitem__'')
Todos son métodos especiales, __len__()
debe devolver el número de elementos, __getitem__(i)
debe devolver un elemento (en secuencia es i -ésimo ítem, pero no con mapeo), __getitem__(slice(start, stop, step))
debería devolver subsecuencia, y __setitem__
y __delitem__
como esperabas. Este es un contrato de este tipo, pero si el objeto realmente hace esto o no depende de si el objeto se adhiere o no al contrato.
Tenga en cuenta que la función anterior también devolverá True
para la asignación, por ejemplo, dict
, ya que la asignación también tiene estos métodos. Para superar esto, puedes hacer un trabajo más pesado :
def is_sequence(obj):
try:
len(obj)
obj[0:0]
return True
except TypeError:
return False
Pero la mayoría de las veces no necesita esto, simplemente haga lo que quiera como si el objeto fuera una secuencia y atrape una excepción si lo desea. Esto es más pitónico.
La documentación de Python 2.6.5 describe los siguientes tipos de secuencia: cadena, cadena Unicode, lista, tupla, búfer y xrange.
def isSequence(obj):
return type(obj) in [str, unicode, list, tuple, buffer, xrange]
por qué preguntar por qué
intente obtener una longitud y si la excepción devuelve falso
def haslength(seq):
try:
len(seq)
except:
return False
return True
iter(x)
generará un TypeError
si no se puede iterar con x
, pero esa comprobación "acepta" conjuntos y diccionarios, aunque "rechaza" otras secuencias no tales como None
y números.
Por otro lado, las cadenas (que la mayoría de las aplicaciones desean considerar como "elementos individuales" en lugar de secuencias) son, de hecho, secuencias (por lo que cualquier prueba, a menos que sea especial para cadenas, confirmará que lo son). Entonces, tales controles simples a menudo no son suficientes.
En Python 2.6 y mejor, se introdujeron las clases base abstractas y, entre otras características potentes, ofrecen un soporte más bueno y sistemático para dicha "verificación de categoría".
>>> import collections
>>> isinstance([], collections.Sequence)
True
>>> isinstance((), collections.Sequence)
True
>>> isinstance(23, collections.Sequence)
False
>>> isinstance(''foo'', collections.Sequence)
True
>>> isinstance({}, collections.Sequence)
False
>>> isinstance(set(), collections.Sequence)
False
Notará que las cadenas todavía se consideran "una secuencia" (ya que lo son ), pero al menos obtiene los dictados y los conjuntos fuera del camino. Si desea excluir cadenas de su concepto de "secuencias en ser", podría usar collections.MutableSequence
(pero eso también excluye tuplas, que, como cadenas, son secuencias, pero no son mutables), o hacerlo explícitamente:
import collections
def issequenceforme(obj):
if isinstance(obj, basestring):
return False
return isinstance(obj, collections.Sequence)
Sazone al gusto y sirva caliente! -)