2015-07-06 12 views
6

mam manekina przykład pojemnika iteratora poniżej (prawdziwa odczytuje plik zbyt duży, aby zmieścić się w pamięci):Jak sprawdzić, czy iterator jest w rzeczywistości kontenerem iteracyjnym?

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 

To pozwala mi iteracyjne nad wartością więcej niż raz abym można zaimplementować coś takiego:

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)) 

Jak mogę sprawdzić w funkcji normalizować, że mam być przekazany pojemnik iteracyjnej zamiast zwykłego generatora?

+0

Nie musisz od razu czytać pliku w pamięci, więc dlaczego tego potrzebujesz? –

+1

Co Padraic powiedział. Jeśli chcesz wykonać wiele przebiegów przez duży plik, po prostu użyj jego metody '.seek()' do przewinięcia. –

+1

Czy możesz edytować swój kod, aby działał? Dodaj parametr 'self' do' __init__' i użyj 'self.max_value' do' __iter__' –

Odpowiedz

8

Po pierwsze: nie ma czegoś takiego jak pojemnik iteratora . Masz iterowalny.

W iteracji powstaje iterator. Wszelkie iterator jest również iterable, ale produkuje sam jako iterator:

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

Nie masz iterator jeśli test iter(ob) is ob jest fałszywe.

2

Można sprawdzić, czy masz iterator (jest zużywana raz next podnosi wyjątek StopIteration) vs tylko iterable (można prawdopodobnie powtórzyć na wiele razy) za pomocą collections.abcmodule. Oto przykład:

from collections.abc import Iterable, Iterator 

def my_iterator(): 
    yield 1 

i = my_iterator() 
a = [] 

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

Co sprawia my_iterator() się Iterator jest obecność obu magicznych sposobach __next__ i __iter__ (a przy okazji, w zasadzie to, co dzieje się za kulisami podczas rozmowy isinstance na collections.abc abstrakcyjnej podstawy klasa jest testem na obecność pewnych magicznych metod).

Zauważ, że iterator jest również Iterable, jak jest pusta lista (czyli oba mają magiczną metodę __iter__):

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

Należy również zauważyć, as was pointed out in Martijn Pieters' answer, że kiedy stosuje się ogólny iter() funkcja do obu, można dostać iterator:

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

różnica między [] i tutaj jest to, że my_iterator()iter(my_iterator())zwraca się jako jako iterator, natomiast iter([]) generuje nowy iterator za każdym razem.

Jak już wspomniano w tej samej odpowiedzi MP, powyższy obiekt nie jest "kontenerem iteratora". Jest to obiekt iterowalny, tzn. "Iterowalny". To, czy "zawiera" coś, czy nie, nie jest tak naprawdę powiązane; pojęcie zawierania reprezentuje abstrakcyjna klasa podstawowa Container. A Container może być iterowalny, ale niekoniecznie musi.