Czy iteratory Pythona nie mają hasNext
metody?
Czy iteratory Pythona nie mają hasNext
metody?
Odpowiedzi:
Nie, nie ma takiej metody. Koniec iteracji jest oznaczony wyjątkiem. Zobacz dokumentację .
unnext()
metoda umieszczania pierwszego elementu z powrotem po sprawdzeniu, czy istnieje przez wywołanie next()
.
yield
czy nie). Oczywiście nie jest trudno napisać adapter, który przechowuje wyniki next()
i zapewnia has_next()
i move_next()
.
hasNext()
metody (do tworzenia, buforowania i zwracania wartości true w przypadku sukcesu lub zwracania fałszu w przypadku niepowodzenia). Wtedy oba hasNext()
i next()
będą zależeć od wspólnej getNext()
metody bazowej i elementu w pamięci podręcznej. Naprawdę nie rozumiem, dlaczego next()
nie miałoby być w bibliotece standardowej, skoro tak łatwo jest zaimplementować adapter, który to zapewnia.
next()
i hasNext()
metody, a nie tylko hipotetycznej biblioteki Pythona). Więc tak, next()
i hasNext()
staje się trudne, jeśli zawartość skanowanego strumienia zależy od tego, kiedy elementy są odczytywane.
Istnieje alternatywa dla StopIteration
używania next(iterator, default_value)
.
Na przykład:
>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None
Możesz więc wykryć dla None
lub inną wstępnie określoną wartość na końcu iteratora, jeśli nie chcesz korzystać z wyjątku.
sentinel = object()
i next(iterator, sentinel)
oraz test z is
.
unittest.mock.sentinel
obiektu, który pozwala na napisanie wyraźnego, next(a, sentinel.END_OF_ITERATION)
a następnieif next(...) == sentinel.END_OF_ITERATION
Jeśli naprawdę potrzebujesz do has-next
funkcjonalności (bo jesteś po prostu wiernie transkrypcji algorytm od implementacji referencyjnej w Javie, powiedzmy, albo dlatego piszesz prototyp, że będzie potrzeba być łatwo przepisywane na Javie, kiedy jest gotowy), to łatwo zdobądź go z małą klasą wrapper. Na przykład:
class hn_wrapper(object):
def __init__(self, it):
self.it = iter(it)
self._hasnext = None
def __iter__(self): return self
def next(self):
if self._hasnext:
result = self._thenext
else:
result = next(self.it)
self._hasnext = None
return result
def hasnext(self):
if self._hasnext is None:
try: self._thenext = next(self.it)
except StopIteration: self._hasnext = False
else: self._hasnext = True
return self._hasnext
teraz coś w stylu
x = hn_wrapper('ciao')
while x.hasnext(): print next(x)
emituje
c
i
a
o
jako wymagane.
Zwróć uwagę, że użycie programu next(sel.it)
jako wbudowanego wymaga Pythona 2.6 lub nowszego; jeśli używasz starszej wersji Pythona, użyj self.it.next()
zamiast tego (i podobnie next(x)
w przykładzie użycia). [[Możesz rozsądnie pomyśleć, że ta uwaga jest zbędna, ponieważ Python 2.6 istnieje już od ponad roku - ale częściej niż nie, kiedy używam funkcji Pythona 2.6 w odpowiedzi, jakiś komentator lub inny czuje się zobowiązany do wskazania że są cechami 2.6, więc chociaż raz staram się uprzedzić takie komentarze ;-)]]
has_next
metodę. Konstrukcja Pythona uniemożliwia, powiedzmy, użycie filter
do sprawdzenia, czy tablica zawiera element pasujący do danego predykatu. Arogancja i krótkowzroczność społeczności Pythona jest oszałamiająca.
TypeError: iter() returned non-iterator
map
i any
zamiast filter
, ale możesz użyć SENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINEL
lub zapomnieć a SENTINEL
i po prostu użyć try: except
i złapać StopIteration
.
Oprócz wszystkich wzmianek o StopIteration, pętla „for” w Pythonie po prostu robi to, co chcesz:
>>> it = iter("hello")
>>> for i in it:
... print i
...
h
e
l
l
o
Wypróbuj metodę __length_hint __ () z dowolnego obiektu iteratora:
iter(...).__length_hint__() > 0
__init__
i __main__
? Imho, to trochę bałaganu, bez względu na to, czy próbujesz to usprawiedliwić.
hasNext
co nieco przekłada się na StopIteration
wyjątek, np .:
>>> it = iter("hello")
>>> it.next()
'h'
>>> it.next()
'e'
>>> it.next()
'l'
>>> it.next()
'l'
>>> it.next()
'o'
>>> it.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
StopIteration
dokumenty: http://docs.python.org/library/exceptions.html#exceptions.StopIterationNie. Najbardziej podobną koncepcją jest najprawdopodobniej wyjątek StopIteration.
Uważam, że python ma po prostu next () i zgodnie z dokumentem zgłasza wyjątek, że nie ma więcej elementów.
Przykład użycia, który doprowadził mnie do wyszukiwania tego, jest następujący
def setfrom(self,f):
"""Set from iterable f"""
fi = iter(f)
for i in range(self.n):
try:
x = next(fi)
except StopIteration:
fi = iter(f)
x = next(fi)
self.a[i] = x
gdzie jest dostępna funkcja hasnext (), można to zrobić
def setfrom(self,f):
"""Set from iterable f"""
fi = iter(f)
for i in range(self.n):
if not hasnext(fi):
fi = iter(f) # restart
self.a[i] = next(fi)
który dla mnie jest czystszy. Oczywiście możesz obejść problemy, definiując klasy narzędzi, ale co się wtedy dzieje, to mnożenie się dwudziestu różnych, prawie równoważnych obejść, z których każdy ma ich dziwactwa, a jeśli chcesz ponownie użyć kodu, który używa innych obejść, musisz albo mieć wiele zbliżonych do odpowiedników w jednej aplikacji lub przejść dookoła, wybierając i przepisując kod, aby zastosować to samo podejście. Zasada „zrób to raz i zrób to dobrze” kończy się niepowodzeniem.
Ponadto sam iterator musi mieć wewnętrzną kontrolę „hasnext”, aby sprawdzić, czy musi zgłosić wyjątek. To wewnętrzne sprawdzenie jest następnie ukrywane, więc należy je przetestować, próbując pobrać element, przechwytując wyjątek i uruchamiając procedurę obsługi, jeśli zostanie rzucona. To niepotrzebne ukrywanie IMO.
Sugerowanym sposobem jest zatrzymanie . Zobacz przykład Fibonacciego z tutorialspoint
#!usr/bin/python3
import sys
def fibonacci(n): #generator function
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(5) #f is iterator object
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
Sposób, w jaki rozwiązałem ten problem, to jak dotąd zliczanie iterowanych obiektów. Chciałem iterować zestaw przy użyciu wywołań metody instancji. Ponieważ znałem długość zestawu i liczbę policzonych dotychczas elementów, skutecznie miałem hasNext
metodę.
Prosta wersja mojego kodu:
class Iterator:
# s is a string, say
def __init__(self, s):
self.s = set(list(s))
self.done = False
self.iter = iter(s)
self.charCount = 0
def next(self):
if self.done:
return None
self.char = next(self.iter)
self.charCount += 1
self.done = (self.charCount < len(self.s))
return self.char
def hasMore(self):
return not self.done
Oczywiście przykład jest zabawkowy, ale masz pomysł. To nie zadziała w przypadkach, gdy nie ma możliwości uzyskania długości iterowalnej, jak generator itp.