web-dev-qa-db-fra.com

Fonction générateur vide Python

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?

71
Konstantin Weitz

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]

Pourquoi ne pas simplement utiliser 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.

96
senderle
iter(())

Vous n'avez pas {requis} _ un générateur. Allez les gars!

59
Zectbumo

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.

41
DSM

Une autre option est:

(_ for _ in ())
12
Ben Reynwar

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).

6
eddiewould

Doit-il s'agir d'une fonction génératrice? Si non, que diriez-vous

def f():
    return iter([])
4
unutbu

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

3
Jurjen Bos

Pour ceux d'entre vous qui ont réellement besoin d'une fonction et d'un générateur

empty = lambda: (_ for _ in ())
0
Zectbumo
generator = (item for item in [])
0
user2113422