Você pode usar return
uma vez em um gerador; ele interrompe a iteração sem produzir nada e, portanto, fornece uma alternativa explícita para deixar a função sair do escopo. Portanto, use yield
para transformar a função em um gerador, mas precedê-lo com return
para encerrar o gerador antes de produzir qualquer coisa.
>>> def f():
... return
... yield
...
>>> list(f())
[]
Não tenho certeza se é muito melhor do que o que você tem - ele apenas substitui uma if
instrução no-op por uma instrução no-op yield
. Mas é mais idiomático. Observe que apenas usar yield
não funciona.
>>> def f():
... yield
...
>>> list(f())
[None]
Por que não apenas usar iter(())
?
Esta pergunta pergunta especificamente sobre uma função de gerador vazia . Por esse motivo, considero que seja uma questão sobre a consistência interna da sintaxe do Python, em vez de uma questão sobre a melhor maneira de criar um iterador vazio em geral.
Se a dúvida for realmente sobre a melhor maneira de criar um iterador vazio, você pode concordar com o Zectbumo sobre o uso iter(())
. Porém, é importante observar que iter(())
não retorna uma função! Ele retorna diretamente um iterável vazio. Suponha que você esteja trabalhando com uma API que espera um chamável que retorna um iterável. Você terá que fazer algo assim:
def empty():
return iter(())
(O crédito deve ir para Unutbu por fornecer a primeira versão correta desta resposta.)
Agora, você pode achar o acima mais claro, mas posso imaginar situações em que seria menos claro. Considere este exemplo de uma longa lista de definições de funções geradoras (inventadas):
def zeros():
while True:
yield 0
def ones():
while True:
yield 1
...
No final dessa longa lista, prefiro ver algo com um yield
, como este:
def empty():
return
yield
ou, no Python 3.3 e superior (conforme sugerido pelo DSM ), isto:
def empty():
yield from ()
A presença da yield
palavra-chave deixa claro à primeira vista que se trata apenas de mais uma função geradora, exatamente como todas as outras. Demora um pouco mais para ver que a iter(())
versão está fazendo a mesma coisa.
É uma diferença sutil, mas honestamente acho que as yield
funções baseadas em-são mais legíveis e sustentáveis.
if False: yield
mas ainda um tanto confuso para pessoas que não conhecem esse padrãoitertools.empty()
.return
significa algo diferente dentro dos geradores. É mais parecidobreak
.False
.Você não precisa de um gerador. Vamos, pessoal!
fonte
iter([])
pelo simples fato de que()
é uma constante enquanto[]
pode instanciar um novo objeto de lista na memória toda vez que é chamado.empty = lambda: iter(())
oudef empty(): return iter(())
.Python 3.3 (porque estou em um
yield from
chute, e porque @senderle roubou meu primeiro pensamento):Mas tenho que admitir que estou tendo dificuldade em encontrar um caso de uso para o qual
iter([])
ou(x)range(0)
não funcione igualmente bem.fonte
return; yield
ouif False: yield None
.iter([])
ou(x)range(0)
não funcione igualmente bem." -> Não tenho certeza do que(x)range(0)
é, mas um caso de uso pode ser um método que deve ser substituído por um gerador completo em algumas das classes herdadas. Para fins de consistência, você deseja que até mesmo o básico, do qual os outros herdam, retorne um gerador exatamente como aqueles que o substituíram.Outra opção é:
fonte
Generator[str, Any, None]
Deve ser uma função geradora? Se não, que tal
fonte
A maneira "padrão" de fazer um iterador vazio parece ser iter ([]). Eu sugeri tornar [] o argumento padrão para iter (); isso foi rejeitado com bons argumentos, consulte http://bugs.python.org/issue25215 - Jurjen
fonte
Como disse @senderle, use isto:
Estou escrevendo esta resposta principalmente para compartilhar outra justificativa para isso.
Uma razão para escolher esta solução acima das outras é que ela é ótima no que diz respeito ao intérprete.
Como podemos ver, o
empty_return
tem exatamente o mesmo bytecode de uma função vazia regular; o resto executa uma série de outras operações que não mudam o comportamento de qualquer maneira. A única diferença entreempty_return
enoop
é que o primeiro tem o sinalizador gerador definido:Obviamente, a força desse argumento depende muito da implementação específica do Python em uso; um intérprete alternativo suficientemente inteligente pode perceber que as outras operações não significam nada útil e otimizá-las. No entanto, mesmo se essas otimizações estiverem presentes, elas exigem que o intérprete gaste tempo realizando-as e se proteja contra suposições de otimização sendo quebradas, como o
iter
identificador no escopo global sendo rebote para outra coisa (mesmo que isso provavelmente indique um bug se realmente aconteceu). No caso deempty_return
simplesmente não haver nada para otimizar, mesmo o relativamente ingênuo CPython não perderá tempo com operações espúrias.fonte
fonte