Pergunta

Eu sou um grande fã de Python da para ... else sintaxe - é surpreendente como muitas vezes é o caso, e como efetivamente ele pode simplificar o código

.

No entanto, eu não descobri uma boa maneira de usá-lo em um gerador, por exemplo:

def iterate(i):
    for value in i:
        yield value
    else:
        print 'i is empty'

No exemplo acima, eu gostaria a declaração print a ser executado somente se i está vazio. No entanto, como else apenas aspectos break e return, é sempre executado, independentemente da duração da i.

Se é impossível usar for...else desta forma, qual é a melhor abordagem para isso para que a declaração print só é executado quando nada é produzido?

Foi útil?

Solução

Você está quebrando a definição de um gerador, que deve lançar uma exceção StopIteration quando iteração é completo (que é automaticamente manipulado por uma instrução de retorno em uma função de gerador)

Assim:

def iterate(i):
    for value in i:
        yield value
    return

Melhor para deixar o punho código chamando o caso de um iterador vazio:

count = 0
for value in iterate(range([])):
    print value
    count += 1
else:
    if count == 0:
        print "list was empty"

Pode ser uma maneira mais limpa de fazer o acima, mas que deve funcionar bem, e não se enquadra em qualquer um dos comum 'tratar um iterador como uma lista de' armadilhas abaixo.

Outras dicas

Existem algumas maneiras de fazer isso. Você pode sempre usar o Iterator diretamente:

def iterate(i):
    try:
        i_iter = iter(i)
        next = i_iter.next()
    except StopIteration:
        print 'i is empty'
        return

    while True:
        yield next
        next = i_iter.next()

Mas se você sabe mais sobre o que esperar do i argumento, você pode ser mais conciso:

def iterate(i):
    if i:  # or if len(i) == 0
        for next in i:
            yield next
    else:
        print 'i is empty'
        raise StopIteration()

Resumindo algumas das respostas anteriores, poderia ser resolvido assim:

def iterate(i):
    empty = True
    for value in i:
        yield value
        empty = False

    if empty:
        print "empty"

então não há realmente nenhuma cláusula "else" envolvida.

Como você notar, for..else só detecta um break. Portanto, é aplicável apenas quando você olha para alguma coisa e, em seguida, parada .

Não é aplicável ao seu propósito não porque é um gerador, mas porque você quer processar todos os elementos, sem parar (porque você quer produzir todos eles, mas esse não é o ponto).

Assim gerador ou não, você realmente precisa de um boolean, como na solução de Ber.

Se é impossível usar para ... else, desta forma, o que é a melhor abordagem para isso para que a declaração de impressão só é executado quando nada é produzido?

máximo que posso pensar:


>>> empty = True
>>> for i in [1,2]:
...     empty = False
... if empty:
...     print 'empty'
...
>>>
>>>
>>> empty = True
>>> for i in []:
...     empty = False
... if empty:
...    print 'empty'
...
empty
>>>

E a simples if-else?

def iterate(i):
    if len(i) == 0: print 'i is empty'
    else:
        for value in i:
            yield value
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top