2010-06-11 9 views

Respuesta

37

En Python 2.6 o mejor, el lenguaje diseñada-in para estos controles de comportamiento es una "verificación de la pertenencia" con el clase base abstracta en el módulo collections de la biblioteca estándar:

>>> import collections 
>>> isinstance('ciao', collections.Iterable) 
True 
>>> isinstance(23, collections.Iterable) 
False 
>>> isinstance(xrange(23), collections.Iterable) 
True 

de hecho, este tipo de controles es la razón fundamental del diseño de las nuevas clases de base abstracta (un segundo importante es proporcionar "funcionalidad mixin" de alguna casos, que es por eso que son ABCth rath Más que solo interfaces, pero eso no se aplica a collections.Iterable, existe estrictamente para permitir tales controles con isinstance o issubclass). Los ABC permiten que las clases que realmente no heredan de ellos se "registren" como subclases de todos modos, de modo que dichas clases puedan ser "subclases" del ABC para dichas verificaciones; y, pueden realizar internamente todas las comprobaciones necesarias para métodos especiales (__iter__ en este caso), por lo que no es necesario.

Si le pegan con versiones anteriores de Python, "es mejor pedir perdón que pedir permiso":

def isiterable(x): 
    try: iter(x) 
    except TypeError: return False 
    else: return True 

pero eso no es tan rápida y concisa como el nuevo enfoque.

Tenga en cuenta que para este caso especial a menudo querrá cadenas de casos especiales (que son iterables pero la mayoría de los contextos de aplicación desea tratar como "escalares" de todos modos). Independientemente del enfoque que utiliza para comprobar iterableness, si usted necesita tal carcasa especial simplemente escriba un cheque por isinstance(x, basestring) - por ejemplo:

def reallyiterable(x): 
    return not isinstance(x, basestring) and isinstance(x, collections.Iterable) 

Editar: como se señala en un comentario, la cuestión se centra en si un objeto es un iter *** ator *** en lugar de si iter *** able *** (todos los iteradores son iterables, pero no al revés - no todos los iterables son iteradores). isinstance(x, collections.Iterator) es la manera perfectamente análoga de verificar específicamente esa condición.

+9

Las preguntas se preguntan si un objeto es un iterador, no si es iterable. Por lo tanto, debe usar colecciones. Identificador en lugar de colecciones. Es posible –

+0

@Dave, derecha, déjeme editar para aclarar. –

9

Un objeto es iterable si implementa el protocolo de iterador.
Usted puede comprobar la presencia de __iter__() método con:

hasattr(object,'__iter__') 

en Python 2.x este enfoque no encuentra objetos str y otros tipos de secuencias integradas como Unicode, xrange, tampón. Funciona en Python 3.

Otra forma es poner a prueba con el método iter:

try: 
    iter(object) 
except TypeError: 
    #not iterable 
+1

Crear un iterador puede ser costoso, mientras que verificar la existencia del atributo siempre es * rápido *. –

4

Para ser un iterador un objeto debe pasar tres pruebas:

  • obj tiene un método __iter__
  • obj tiene un método next (o __next__ en Python 3)
  • obj.__iter__() rendimientos obj

Por lo tanto, una prueba de rollo propio parecerse a:

def is_iterator(obj): 
    if (
      hasattr(obj, '__iter__') and 
      hasattr(obj, 'next') and  # or __next__ in Python 3 
      callable(obj.__iter__) and 
      obj.__iter__() is obj 
     ): 
     return True 
    else: 
     return False 
+0

¿Llamar a 'obj .__ iter __()' corre el riesgo de cambiar algo? –

+0

@ BobStein-VisiBone: solo si el objeto tiene errores. –

Cuestiones relacionadas