Os iteradores Python não têm um hasNext
método?
Os iteradores Python não têm um hasNext
método?
Respostas:
Não, não existe esse método. O final da iteração é indicado por uma exceção. Veja a documentação .
unnext()
método para colocar o primeiro elemento de volta depois de verificar se ele existe chamando next()
.
yield
ou não). Obviamente, não é difícil escrever um adaptador que armazene o resultado next()
e forneça has_next()
e move_next()
.
hasNext()
método (produzir, armazenar em cache e retornar verdadeiro com êxito ou falso com falha). Em seguida, ambos hasNext()
e next()
dependeriam de um getNext()
método subjacente comum e de um item em cache. Realmente não vejo por next()
que não deveria estar na biblioteca padrão se é tão fácil implementar um adaptador que o fornece.
next()
e fornecimento de biblioteca hasNext()
, não apenas uma hipotética biblioteca Python). Então, sim, next()
e hasNext()
se torna complicado se o conteúdo do fluxo que está sendo verificado depende de quando os elementos são lidos.
Há uma alternativa para o StopIteration
usando next(iterator, default_value)
.
Para exapmle:
>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None
Portanto, você pode detectar None
ou outro valor pré-especificado para o final do iterador, se não desejar a exceção.
sentinel = object()
e next(iterator, sentinel)
e teste com is
.
unittest.mock.sentinel
objeto que permite que você escreva uma explícita next(a, sentinel.END_OF_ITERATION)
e depoisif next(...) == sentinel.END_OF_ITERATION
Se você realmente precisa de uma has-next
funcionalidade (porque você está apenas fielmente transcrever um algoritmo de uma implementação de referência em Java, por exemplo, ou porque você está escrevendo um protótipo que vai precisar ser facilmente transcrito para Java quando é terminado), é fácil obtenha-o com uma pequena classe de wrapper. Por exemplo:
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
agora algo como
x = hn_wrapper('ciao')
while x.hasnext(): print next(x)
emite
c
i
a
o
como requerido.
Observe que o uso de next(sel.it)
como embutido requer Python 2.6 ou superior; se você estiver usando uma versão mais antiga do Python, use self.it.next()
(e da mesma forma next(x)
no exemplo de uso). [[Você pode razoavelmente achar que esta nota é redundante, já que o Python 2.6 existe há mais de um ano - mas mais frequentemente do que não quando eu uso os recursos do Python 2.6 em uma resposta, algum comentarista ou outro se sente obrigado a apontar que eles são recursos do 2.6, então estou tentando impedir esses comentários pela primeira vez ;-)]]
has_next
método. O design do Python torna impossível, digamos, usar filter
para verificar se uma matriz contém um elemento correspondente a um determinado predicado. A arrogância e a miopia da comunidade Python são impressionantes.
TypeError: iter() returned non-iterator
map
e any
não filter
, mas poderia usar SENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINEL
ou esquecer um SENTINEL
e apenas usar try: except
e capturar o arquivo StopIteration
.
Além de todas as menções de StopIteration, o loop "for" do Python simplesmente faz o que você deseja:
>>> it = iter("hello")
>>> for i in it:
... print i
...
h
e
l
l
o
Experimente o método __length_hint __ () de qualquer objeto iterador:
iter(...).__length_hint__() > 0
__init__
e __main__
? Imho, é um pouco confuso, não importa o que você tente justificar.
hasNext
um pouco se traduz na StopIteration
exceção, por exemplo:
>>> 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
docs: http://docs.python.org/library/exceptions.html#exceptions.StopIterationNão. O conceito mais semelhante é provavelmente uma exceção StopIteration.
Acredito que o python apenas possui next () e, de acordo com o documento, lança uma exceção: não há mais elementos.
O caso de uso que me levou a procurar isso é o seguinte
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
onde hasnext () está disponível, pode-se fazer
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)
o que para mim é mais limpo. Obviamente, você pode solucionar problemas definindo classes de utilitário, mas o que acontece é que você tem uma proliferação de vinte e diferentes soluções alternativas quase equivalentes, cada uma com suas peculiaridades, e se você deseja reutilizar o código que usa soluções alternativas diferentes, é necessário tenha vários equivalentes quase em seu único aplicativo ou escolha e reescreva o código para usar a mesma abordagem. A máxima "faça uma vez e faça bem" falha muito.
Além disso, o próprio iterador precisa ter uma verificação interna 'hasnext' para executar para ver se precisa gerar uma exceção. Essa verificação interna é ocultada para que precise ser testada tentando obter um item, capturando a exceção e executando o manipulador, se acionado. Isso é desnecessário ocultar o IMO.
A maneira sugerida é StopIteration . Por favor, veja o exemplo de Fibonacci do 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()
A maneira como resolvi meu problema é manter a contagem do número de objetos repetidos até o momento. Eu queria iterar sobre um conjunto usando chamadas para um método de instância. Como eu sabia a duração do set e o número de itens contados até agora, eu efetivamente tive umahasNext
método.
Uma versão simples do meu código:
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
Obviamente, o exemplo é de brinquedo, mas você entendeu. Isso não funcionará nos casos em que não há como obter o comprimento do iterável, como um gerador etc.