2010-06-11 12 views

risposta

37

In Python 2.6 o meglio, l'idioma progettato a tali controlli comportamentali è un "controllo di appartenenza" con il classe di base astratta nel modulo collections della libreria standard:

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

in effetti, questo tipo di controlli è la ragione di progettazione principale per le nuove classi di base astratta (un secondo importante è quello di fornire "la funzionalità mixin" in qualche casi, che è il motivo per cui sono ABC rath er che solo le interfacce - ma non si applica a collections.Iterable, esiste rigorosamente per consentire tali controlli con isinstance o issubclass). Gli ABC consentono alle classi che in realtà non ereditano da loro di essere "registrate" come sottoclassi in ogni caso, così che tali classi possano essere "sottoclassi" dell'ABC per tali controlli; e, in questo caso, possono eseguire internamente tutti i controlli necessari per i metodi speciali (__iter__), quindi non è necessario.

Se sei bloccato con vecchie versioni di Python, "è meglio chiedere perdono che il permesso":

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

ma che non è il più veloce e conciso come il nuovo approccio.

Si noti che per questo caso particolare spesso si vogliono stringhe di casi speciali (che sono iterabili ma la maggior parte dei contesti applicativi vuole trattare come "scalari" comunque). Qualunque sia l'approccio che si sta utilizzando per controllare iterableness, se avete bisogno di tale involucro speciale solo anteporre un assegno per isinstance(x, basestring) - ad esempio:

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

Edit: come sottolineato in un commento, la questione si concentra sul fatto che un oggetto è un iter *** ator *** piuttosto che iter *** *** in grado *** (tutti gli iteratori sono iterabili, ma non viceversa - non tutti gli iterabili sono iteratori). isinstance(x, collections.Iterator) è il modo perfettamente analogo per verificare specificamente tale condizione.

+9

Le domande chiedono se un oggetto è un iteratore, non se è iterabile. Quindi dovresti usare collections.Iterator invece di collections.Iterable –

+0

@Dave, giusto, fammi modificare per chiarire. –

9

Un oggetto è iterabile se implementa il protocollo iteratore.
Si potrebbe verificare la presenza di __iter__() metodo con:

hasattr(object,'__iter__') 

in Python 2.x questo approccio non trova oggetti str e altri tipi di sequenze integrate come unicode, xrange, tampone. Funziona in Python 3.

Un altro modo è quello di testare con metodo iter:

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

La creazione di iteratore può essere costosa mentre la verifica dell'esistenza degli attributi è sempre * veloce *. –

4

Per essere un iteratore un oggetto deve superare tre prove:

  • obj ha un metodo __iter__
  • obj ha un metodo next (o __next__ in Python 3)
  • obj.__iter__() rendimenti obj

Quindi, un test roll-your-own sarebbe assomiglia 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

Chiamare 'obj .__ iter __()' rischia di cambiare qualcosa? –

+0

@ BobStein-VisiBone: solo se l'oggetto è bacato. –

Problemi correlati