Python: uma iteração sobre uma lista não-vazia, sem cláusula se trata-se vazio. Por quê?
-
22-08-2019 - |
Pergunta
Como pode uma iteração através de uma sequência não-vazia, sem filtragem e nenhuma agregação (sum()
, etc), rendimento nada?
Considere um exemplo simples:
sequence = ['a', 'b', 'c']
list((el, ord(el)) for el in sequence)
Esta [('a', 97), ('b', 98), ('c', 99)]
rendimentos como esperado.
Agora, basta trocar o ord(el)
fora para uma expressão que dá o primeiro valor de algum gerador usando (...).next()
- perdoar o exemplo artificial:
def odd_integers_up_to_length(str):
return (x for x in xrange(len(str)) if x%2==1)
list((el, odd_integers_up_to_length(el).next()) for el in sequence)
Este rendimentos []
. Sim, lista vazia. Sem ('a',
stuff)
tuplas. Nada.
Mas não estamos filtrando ou agregar ou reduzir. Um gerador de expressão sobre objectos n
sem filtragem ou agregação deve produzir objectos n
, direita? O que está acontecendo?
Solução
odd_integers_up_to_length(el).next()
elevará StopIteration, que não está preso lá, mas é capturado para a expressão gerador de dentro dele, parando-o sem nunca ceder nada.
olhada na primeira iteração, quando o valor é 'a':
>>> odd_integers_up_to_length('a').next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Outras dicas
O que acontece é que a chamada next()
gera uma exceção StopIteration
, que borbulha a pilha para a expressão gerador externo e pára que iteração.
A StopIteration
é o caminho normal para um iterador para sinal de que ele é feito. Geralmente nós não vê-lo, porque geralmente a chamada next()
ocorre dentro de uma construção que consome o iterador, por exemplo, for x in iterator
ou sum(iterator)
. Mas quando chamamos next()
diretamente, somos os responsáveis ??por pegar o StopIteration
. Não fazê-lo um vazamento na abstração, que aqui leva a um comportamento inesperado na iteração externa.
A lição, suponho:. Ter cuidado com chamadas diretas para next()
str é uma palavra-chave reservada, você deve nomear sua variável diferente
Eu também estava a aconselhar sobre a próxima
>>> seq=['a','b','c']
>>> list((el,4) for el in seq)
[('a',4), ('b',4), ('c',4)]
Portanto, não é list
dando-lhe problemas aqui ...