"É mais fácil pedir perdão do que permissão.": Verificar se um iterador tem um próximo elemento não está pedindo permissão. Há situações em que você deseja testar a existência de um próximo elemento sem consumi-lo. Eu aceitaria a solução try catch se houvesse um unnext()método para colocar o primeiro elemento de volta depois de verificar se ele existe chamando next().
Giorgio
15
@Giorgio, não há como saber se existe outro elemento sem executar o código que o gera (você não sabe se o gerador será executado yieldou não). Obviamente, não é difícil escrever um adaptador que armazene o resultado next()e forneça has_next()e move_next().
avakar
5
A mesma idéia pode ser usada para implementar o 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.
Giorgio
3
@LarsH: Você quer dizer, por exemplo, um iterador que lê de um arquivo que pode ser alterado durante a leitura? Concordo que isso pode ser um problema (que afeta qualquer método 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.
Giorgio
239
Há uma alternativa para o StopIterationusando 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 Noneou outro valor pré-especificado para o final do iterador, se não desejar a exceção.
se você usar None como "sentinela", verifique se o seu iterador não possui nenhum Nones. Você também pode fazer sentinel = object()e next(iterator, sentinel)e teste com is.
sam boosalis
1
seguinte @samboosalis eu preferiria usar construído-in unittest.mock.sentinelobjeto que permite que você escreva uma explícita next(a, sentinel.END_OF_ITERATION)e depoisif next(...) == sentinel.END_OF_ITERATION
ClementWalter
este é mais bonita do que a exceção
datdinhquoc
O problema é que, dessa forma, você CONSUME o próximo valor do iterador também. O hasNext em Java não consome o próximo valor.
Alan Franzoni 17/07
39
Se você realmente precisa de uma has-nextfuncionalidade (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 =Nonedef __iter__(self):return self
def next(self):if self._hasnext:
result = self._thenext
else:
result = next(self.it)
self._hasnext =Nonereturn result
def hasnext(self):if self._hasnext isNone:try: self._thenext = next(self.it)exceptStopIteration: self._hasnext =Falseelse: self._hasnext =Truereturn 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 ;-)]]
"Transcrever fielmente um algoritmo de uma implementação de referência em Java" é a pior razão para precisar de um has_nextmétodo. O design do Python torna impossível, digamos, usar filterpara 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.
Jonathan fundido
resposta agradável, eu estou copiando este para ilustration de algum padrão de design tomadas a partir do código Java
madtyn
Eu estou com Python3 e este código me dáTypeError: iter() returned non-iterator
madtyn
1
@JonathanCast não tenho certeza se eu sigo. Em Python, você normalmente usaria mape anynão filter, mas poderia usar SENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINELou esquecer um SENTINELe apenas usar try: excepte capturar o arquivo StopIteration.
Juanpa.arrivillaga 18/09/19
13
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
Eu sempre me perguntei por que diabos python tem todos esses métodos __ xxx __? Eles parecem tão feios.
mP.
6
Pergunta legítima! Geralmente é a sintaxe dos métodos expostos por uma função interna (por exemplo, len, na verdade, está chamando len ). Essa função interna não existe para length_hint, mas na verdade é uma proposta pendente (PEP424).
Fulmicoton
1
@mP. essas funções estão lá, porque às vezes são necessárias. Eles são intencionalmente feios, porque são considerados o método de último recurso: se você os usar, sabe que faz algo não-pitônico e potencialmente perigoso (o que também pode parar de funcionar a qualquer momento).
Arne Babenhauserheide
Gosta __init__e __main__? Imho, é um pouco confuso, não importa o que você tente justificar.
user1363990
5
hasNextum pouco se traduz na StopIterationexceçã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
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)exceptStopIteration:
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):ifnot 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/python3import sys
def fibonacci(n):#generator function
a, b, counter =0,1,0whileTrue:if(counter > n):returnyield a
a, b = b, a + b
counter +=1
f = fibonacci(5)#f is iterator objectwhileTrue:try:print(next(f), end=" ")exceptStopIteration:
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.
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.
Respostas:
Não, não existe esse método. O final da iteração é indicado por uma exceção. Veja a documentação .
fonte
unnext()
método para colocar o primeiro elemento de volta depois de verificar se ele existe chamandonext()
.yield
ou não). Obviamente, não é difícil escrever um adaptador que armazene o resultadonext()
e forneçahas_next()
emove_next()
.hasNext()
método (produzir, armazenar em cache e retornar verdadeiro com êxito ou falso com falha). Em seguida, amboshasNext()
enext()
dependeriam de umgetNext()
método subjacente comum e de um item em cache. Realmente não vejo pornext()
que não deveria estar na biblioteca padrão se é tão fácil implementar um adaptador que o fornece.next()
e fornecimento de bibliotecahasNext()
, não apenas uma hipotética biblioteca Python). Então, sim,next()
ehasNext()
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
usandonext(iterator, default_value)
.Para exapmle:
Portanto, você pode detectar
None
ou outro valor pré-especificado para o final do iterador, se não desejar a exceção.fonte
sentinel = object()
enext(iterator, sentinel)
e teste comis
.unittest.mock.sentinel
objeto que permite que você escreva uma explícitanext(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:agora algo como
emite
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, useself.it.next()
(e da mesma formanext(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 ;-)]]fonte
has_next
método. O design do Python torna impossível, digamos, usarfilter
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
eany
nãofilter
, mas poderia usarSENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINEL
ou esquecer umSENTINEL
e apenas usartry: except
e capturar o arquivoStopIteration
.Além de todas as menções de StopIteration, o loop "for" do Python simplesmente faz o que você deseja:
fonte
Experimente o método __length_hint __ () de qualquer objeto iterador:
fonte
__init__
e__main__
? Imho, é um pouco confuso, não importa o que você tente justificar.hasNext
um pouco se traduz naStopIteration
exceção, por exemplo:StopIteration
docs: http://docs.python.org/library/exceptions.html#exceptions.StopIterationfonte
Você pode
tee
usar o iterador,,itertools.tee
e verificarStopIteration
o iterador inicial.fonte
Não. O conceito mais semelhante é provavelmente uma exceção StopIteration.
fonte
Acredito que o python apenas possui next () e, de acordo com o documento, lança uma exceção: não há mais elementos.
http://docs.python.org/library/stdtypes.html#iterator-types
fonte
O caso de uso que me levou a procurar isso é o seguinte
onde hasnext () está disponível, pode-se fazer
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.
fonte
A maneira sugerida é StopIteration . Por favor, veja o exemplo de Fibonacci do tutorialspoint
fonte
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 uma
hasNext
método.Uma versão simples do meu código:
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.
fonte