2015-07-06 5 views
6

ich ein Dummy Beispiel eines Iterators Behälter haben unten (der echte liest eine Datei zu groß in den Speicher zu passen):Wie überprüfe ich, ob ein Iterator tatsächlich ein Iterator-Container ist?

class DummyIterator: 
    def __init__(self, max_value): 
     self.max_value = max_value 

    def __iter__(self): 
     for i in range(self.max_value): 
      yield i 

def regular_dummy_iterator(max_value): 
    for i in range(max_value): 
     yield i 

Dies ermöglicht es mir über den Wert mehr als einmal, so dass ich iterieren so etwas wie dies umsetzen kann:

def normalise(data): 
    total = sum(i for i in data) 
    for val in data: 
     yield val/total 

# this works when I call next() 
normalise(DummyIterator(100)) 

# this doesn't work when I call next() 
normalise(regular_dummy_iterator(100)) 

Wie prüfe ich in der normalisieren-Funktion, die ich als ein normaler Generator einen Iterator Behälter eher weitergegeben bin zu werden?

+0

Sie müssen die Datei in den Speicher so auf einmal nicht lesen, warum diese brauchen? –

+1

Was Padraic gesagt hat. Wenn Sie mehrere Pässe über eine große Datei ausführen müssen, verwenden Sie einfach ihre '.seek()' - Methode, um sie zurückzuspulen. –

+1

Können Sie Ihren Code so bearbeiten, dass er lauffähig ist? Füge 'self' Parameter zu' __init__' hinzu und benutze 'self.max_value' in' __iter__' –

Antwort

8

Vor allem: Es gibt keine Iterator-Container. Sie haben eine iterable.

Ein iterable erzeugt einen Iterator. Jeder Iterator ist auch ein iterable, sondern produziert selbst als Iterator:

>>> list_iter = iter([]) 
>>> iter(list_iter) is list_iter 
True 

Sie haben noch einen Iterator, wenn der iter(ob) is ob Test falsch ist.

2

Sie können testen, ob Sie einen Iterator haben (verbraucht einmal next wirft die StopIteration Ausnahme) vs nur ein iterable (kann wahrscheinlich über mehrere Male wiederholt werden) durch die collections.abcmodule verwenden. Hier ein Beispiel:

from collections.abc import Iterable, Iterator 

def my_iterator(): 
    yield 1 

i = my_iterator() 
a = [] 

isinstance(i, Iterator) # True 
isinstance(a, Iterator) # False 

Was my_iterator() eine Iterator macht, ist die Anwesenheit der beiden __next__ und __iter__ magische Methoden (und übrigens, im Grunde, was hinter den Kulissen geschieht, wenn Sie anrufen isinstance auf einem collections.abc abstrakte Basis Klasse ist ein Test für das Vorhandensein bestimmter magischer Methoden).

Beachten Sie, dass ein Iterator ist auch ein Iterable, wie die leere Liste (dh haben beide die __iter__ magische Methode):

isinstance(i, Iterable) # True 
isinstance(a, Iterable) # True 

Beachten Sie auch, as was pointed out in Martijn Pieters' answer, dass, wenn Sie die allgemeine iter() anwenden Funktion für beide, Sie einen Iterator erhalten:

isinstance(iter(my_iterator()), Iterator) # True 
isinstance(iter([])), Iterator) # True 

Der Unterschied zwischen [] und my_iterator() ist, dass iter(my_iterator())sich zurückkehr als Iterator, während iter([]) erzeugt eine neue Iterator jedesmal.

Wie bereits in MPs gleichen Antwort erwähnt, Ihr Objekt oben ist kein „Iterator Behälter.“ Es ist ein iterierbares Objekt, d.h. "ein iterierbares". Ob es etwas "enthält", ist nicht wirklich verwandt. Das Konzept von containing wird durch die abstrakte Basisklasse Container repräsentiert. A Container kann iterierbar sein, muss es aber nicht sein.

Verwandte Themen