Vous pouvez utiliser return
une fois dans un générateur; il arrête l'itération sans rien donner, et fournit ainsi une alternative explicite à laisser la fonction s'exécuter hors de portée. Utilisez donc yield
pour transformer la fonction en générateur, mais faites-la précéder de return
pour terminer le générateur avant de donner quoi que ce soit.
>>> def f():
... return
... yield
...
>>> list(f())
[]
Je ne suis pas sûr que ce soit tant mieux que ce que vous avez - cela remplace simplement une if
instruction no-op par une instruction no-op yield
. Mais c'est plus idiomatique. Notez que la simple utilisation yield
ne fonctionne pas.
>>> def f():
... yield
...
>>> list(f())
[None]
Pourquoi ne pas simplement utiliser iter(())
?
Cette question concerne spécifiquement une fonction de générateur vide . Pour cette raison, je considère que c'est une question sur la cohérence interne de la syntaxe de Python, plutôt qu'une question sur la meilleure façon de créer un itérateur vide en général.
Si la question porte en fait sur la meilleure façon de créer un itérateur vide, vous pourriez être d'accord avec Zectbumo sur l'utilisation à la iter(())
place. Cependant, il est important de noter que iter(())
cela ne renvoie pas de fonction! Il renvoie directement un itérable vide. Supposons que vous travaillez avec une API qui attend un appelable qui renvoie un itérable. Vous devrez faire quelque chose comme ceci:
def empty():
return iter(())
(Le mérite revient à Unutbu d' avoir donné la première version correcte de cette réponse.)
Maintenant, vous pouvez trouver ce qui précède plus clair, mais je peux imaginer des situations dans lesquelles ce serait moins clair. Considérez cet exemple d'une longue liste de définitions de fonctions de générateur (artificielles):
def zeros():
while True:
yield 0
def ones():
while True:
yield 1
...
À la fin de cette longue liste, je préfère voir quelque chose avec un yield
dedans, comme ceci:
def empty():
return
yield
ou, dans Python 3.3 et supérieur (comme suggéré par DSM ), ceci:
def empty():
yield from ()
La présence du yield
mot - clé montre clairement au plus bref coup d'œil qu'il ne s'agit que d'une autre fonction de générateur, exactement comme toutes les autres. Il faut un peu plus de temps pour voir que la iter(())
version fait la même chose.
C'est une différence subtile, mais je pense honnêtement que les yield
fonctions basées sont plus lisibles et maintenables.
if False: yield
mais toujours un peu déroutant pour les personnes qui ne connaissent pas ce modèleitertools.empty()
.return
signifie quelque chose de différent à l'intérieur des générateurs. C'est plus commebreak
.False
.Vous n'avez pas besoin d' un générateur. Allez les gars!
la source
iter([])
pour le simple fait qu'il()
s'agit d'une constante alors que[]
peut instancier un nouvel objet liste en mémoire à chaque fois qu'il est appelé.empty = lambda: iter(())
oudef empty(): return iter(())
.tuple_iterator
au lieu de agenerator
. Si vous avez un cas où votre générateur ne doit rien renvoyer, n'utilisez pas cette réponse.Python 3.3 (parce que je suis sur un
yield from
coup de pied, et parce que @senderle m'a volé ma première pensée):Mais je dois admettre que je suis un moment difficile à venir avec un cas d'utilisation de ce pour lequel
iter([])
ou(x)range(0)
ne fonctionnerait pas aussi bien.la source
return; yield
ou l' autreif False: yield None
.iter([])
ou(x)range(0)
ne fonctionnerait pas aussi bien." -> Je ne sais pas ce que(x)range(0)
c'est, mais un cas d'utilisation peut être une méthode censée être remplacée par un générateur complet dans certaines des classes héritées. Pour des raisons de cohérence, vous voudriez que même le générateur de base, dont d'autres héritent, renvoie un générateur comme ceux qui le remplacent.Une autre option est:
la source
Generator[str, Any, None]
Doit-il être une fonction de générateur? Sinon, que diriez-vous
la source
La manière "standard" de créer un itérateur vide semble être iter ([]). J'ai suggéré de faire de [] l'argument par défaut de iter (); cela a été rejeté avec de bons arguments, voir http://bugs.python.org/issue25215 - Jurjen
la source
Comme @senderle l'a dit, utilisez ceci:
J'écris cette réponse principalement pour partager une autre justification.
Une des raisons de choisir cette solution au-dessus des autres est qu'elle est optimale en ce qui concerne l'interprète.
Comme nous pouvons le voir, le
empty_return
a exactement le même bytecode qu'une fonction vide régulière; les autres effectuent un certain nombre d'autres opérations qui ne changent pas le comportement de toute façon. La seule différence entreempty_return
etnoop
est que le premier a le jeu d'indicateurs de générateur:Bien sûr, la force de cet argument est très dépendante de l'implémentation particulière de Python en cours d'utilisation; un interprète alternatif suffisamment intelligent peut remarquer que les autres opérations ne sont pas utiles et les optimiser. Cependant, même si de telles optimisations sont présentes, elles obligent l'interpréteur à passer du temps à les exécuter et à se prémunir contre la rupture des hypothèses d'optimisation, comme le
iter
rebond de l' identifiant à portée globale vers autre chose (même si cela indiquerait très probablement un bogue s'il effectivement arrivé). Dans le cas oùempty_return
il n'y a tout simplement rien à optimiser, même le CPython relativement naïf ne perdra pas de temps sur des opérations parasites.la source
la source
Je veux donner un exemple basé sur la classe puisque nous n'avons encore eu aucune suggestion. Il s'agit d'un itérateur appelable qui ne génère aucun élément. Je pense que c'est une manière simple et descriptive de résoudre le problème.
la source