En python, on peut facilement définir une fonction itérateur, en plaçant le mot-clé de rendement dans le corps de la fonction, tel que:
def gen():
for i in range(100):
yield i
Comment définir une fonction génératrice qui ne génère aucune valeur (génère 0), le code suivant ne fonctionne pas, car python ne peut pas savoir qu'il est censé être un générateur et non une fonction normale:
def empty():
pass
Je pourrais faire quelque chose comme
def empty():
if False:
yield None
Mais ce serait très moche. Existe-t-il un bon moyen de réaliser une fonction itérateur vide?
Vous pouvez utiliser return
une fois dans un générateur; il arrête l'itération sans rien produire, et fournit donc une alternative explicite à laisser la fonction s'épuiser. Utilisez donc yield
pour transformer la fonction en générateur, mais faites-la précéder de return
pour mettre fin au générateur avant de céder quoi que ce soit.
>>> def f():
... return
... yield
...
>>> list(f())
[]
Je ne suis pas sûr que ce soit bien meilleur que ce que vous avez. Il remplace simplement une instruction no-op if
par une instruction no-op yield
. Mais c'est plus idiomatique. Notez que simplement utiliser yield
ne fonctionne pas.
>>> def f():
... yield
...
>>> list(f())
[None]
iter(())
?Cette question concerne spécifiquement une fonction generator vide. Pour cette raison, j’imagine qu’il s’agit d’une question sur la cohérence interne de la syntaxe de Python, plutôt que sur la meilleure façon de créer un itérateur vide en général.
Si question concerne en fait le meilleur moyen de créer un itérateur vide, vous pourriez être d'accord avec Zectbumo pour utiliser plutôt iter(())
. Cependant, il est important de noter que iter(())
ne renvoie pas de fonction! Il retourne directement un itérable vide. Supposons que vous travailliez avec une API qui attend un appelable qui renvoie un itérable. Vous devrez faire quelque chose comme ça:
def empty():
return iter(())
(Le crédit devrait aller à Unutbu pour avoir donné la première version correcte de cette réponse.)
Vous trouverez peut-être ce qui précède plus clair, mais je peux imaginer des situations dans lesquelles ce serait moins clair. Prenons cet exemple d’une longue liste de définitions de fonctions de générateur (élaborées):
def zeros():
while True:
yield 0
def ones():
while True:
yield 1
...
À la fin de cette longue liste, je préférerais voir quelque chose avec un yield
dedans, comme ceci:
def empty():
return
yield
ou, en Python 3.3 et supérieur (comme suggéré par DSM ), ceci:
def empty():
yield from ()
La présence du mot clé yield
indique clairement, au premier coup d'œil, qu'il ne s'agit que d'une autre fonction génératrice, exactement comme toutes les autres. Il faut un peu plus de temps pour voir que la version iter(())
fait la même chose.
C'est une différence subtile, mais honnêtement, je pense que les fonctions basées sur yield
sont plus lisibles et maintenables.
iter(())
Vous n'avez pas {requis} _ un générateur. Allez les gars!
Python 3.3 (parce que je suis sur un yield from
coup, et parce que @senderle a volé ma première pensée):
>>> def f():
... yield from ()
...
>>> list(f())
[]
Mais je dois admettre que j'ai du mal à trouver un cas d'utilisation pour lequel iter([])
ou (x)range(0)
ne fonctionnerait pas aussi bien.
Une autre option est:
(_ for _ in ())
Je préfère ce qui suit:
def foo():
raise StopIteration()
yield
Le "rendement" en fait un générateur alors qu'Exception signifie que Aucun n'est pas inclus dans le résultat (résultat purement vide).
Doit-il s'agir d'une fonction génératrice? Si non, que diriez-vous
def f():
return iter([])
Le moyen "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
Pour ceux d'entre vous qui ont réellement besoin d'une fonction et d'un générateur
empty = lambda: (_ for _ in ())
generator = (item for item in [])