686 votes

En pratique, quelles sont les principales utilisations de la nouvelle syntaxe "yield from" de Python 3.3 ?

J'ai du mal à me faire à l'idée que PEP 380 .

  1. Quelles sont les situations où le "rendement de" est utile ?
  2. Quel est le cas d'utilisation classique ?
  3. Pourquoi le compare-t-on aux micro-filets ?

[mise à jour]

Je comprends maintenant la cause de mes difficultés. J'ai utilisé des générateurs, mais je n'ai jamais vraiment utilisé des coroutines (introduites par PEP-342 ). Malgré certaines similitudes, les générateurs et les coroutines sont fondamentalement deux concepts différents. Comprendre les coroutines (et pas seulement les générateurs) est la clé pour comprendre la nouvelle syntaxe.

IMHO les coroutines sont la fonctionnalité la plus obscure de Python la plupart des livres le font paraître inutile et inintéressant.

Merci pour les grandes réponses, mais un merci spécial à agf et son commentaire lié à Présentations de David Beazley . David rock.

37 votes

16 votes

Vidéo de l'intervention de David Beazley dabeaz.com/coroutines présentation : youtube.com/watch?v=Z_OAlIhXziw

12voto

Jochen Ritzel Points 42916

yield from enchaîne les itérateurs d'une manière efficace :

# chain from itertools:
def chain(*iters):
    for it in iters:
        for item in it:
            yield item

# with the new keyword
def chain(*iters):
    for it in iters:
        yield from it

Comme vous pouvez le voir, il supprime une pure boucle Python. C'est à peu près tout ce qu'il fait, mais l'enchaînement d'itérateurs est un modèle assez courant en Python.

Les threads sont essentiellement une fonctionnalité qui vous permet de sauter hors des fonctions à des points complètement aléatoires et de revenir dans l'état d'une autre fonction. Le superviseur de threads le fait très souvent, de sorte que le programme semble exécuter toutes ces fonctions en même temps. Le problème est que les points sont aléatoires, vous devez donc utiliser le verrouillage pour empêcher le superviseur d'arrêter la fonction à un point problématique.

Les générateurs sont assez semblables aux fils en ce sens : Ils vous permettent de spécifier des points spécifiques (lorsqu'ils sont yield ) où l'on peut entrer et sortir. Lorsqu'ils sont utilisés de cette manière, les générateurs sont appelés coroutines.

Lisez cet excellent tutoriel sur les coroutines en Python pour plus de détails

11 votes

Cette réponse est trompeuse car elle élude la caractéristique principale de "yield from", comme mentionné ci-dessus : le support de send() et throw().

2 votes

@Justin W : Je suppose que ce que vous avez lu avant est en fait trompeur, parce que vous n'avez pas compris que throw()/send()/close() sont yield caractéristiques qui yield from doit évidemment être mis en œuvre correctement car il est censé simplifier le code. De telles trivialités n'ont rien à voir avec l'utilisation.

5 votes

Contestez-vous la réponse de Ben Jackson ci-dessus ? D'après ma lecture de votre réponse, il s'agit essentiellement d'un sucre syntaxique qui suit la transformation du code que vous avez fournie. La réponse de Ben Jackson réfute spécifiquement cette affirmation.

11voto

Yeo Points 938

Dans l'usage appliqué pour le Coroutine d'E/S asynchrone , yield from a un comportement similaire à celui de await dans un fonction coroutine . Les deux sont utilisés pour suspendre l'exécution de la coroutine.

Pour Asyncio, s'il n'y a pas besoin de prendre en charge une version plus ancienne de Python (c'est-à-dire >3.5), async def / await est la syntaxe recommandée pour définir une coroutine. Ainsi, yield from n'est plus nécessaire dans une coroutine.

Mais en général, en dehors d'Asyncio, yield from <sub-generator> a encore un autre usage en itérant les sous-générateur comme mentionné dans la réponse précédente.

4voto

jimifiki Points 1435

Ce code définit une fonction fixed_sum_digits renvoyer un générateur énumérant tous les nombres à six chiffres de telle sorte que la somme des chiffres soit de 20.

def iter_fun(sum, deepness, myString, Total):
    if deepness == 0:
        if sum == Total:
            yield myString
    else:  
        for i in range(min(10, Total - sum + 1)):
            yield from iter_fun(sum + i,deepness - 1,myString + str(i),Total)

def fixed_sum_digits(digits, Tot):
    return iter_fun(0,digits,"",Tot) 

Essayez de l'écrire sans yield from . Si vous trouvez un moyen efficace de le faire, faites-le moi savoir.

Je pense que pour des cas comme celui-ci : visiter les arbres, yield from rend le code plus simple et plus propre.

3voto

DomQ Points 1166

C'est simple, yield from fournit récursion de queue pour les fonctions d'itérateur.

1 votes

C'est génial ! Pouvez-vous fournir un exemple montrant comment yield from facilite la récursion de queue ? Je comprends la récursion de queue et le yield, mais je ne vois pas comment la faire fonctionner en python.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X