4
votes

Python: passer l'argument à l'objet générateur créé par l'expression du générateur?

donc j'ai cet objet gen:

def yld123u(u):
    for i in range(1, 4):
        yield i * u

for i in yld123u(2):
    print(i, end=' ')

que je ne peux utiliser que comme ça:

u = 2  # some user given value
for i in yld123cu:
    print(i, end=' ')

y a-t-il une syntaxe à éviter la ligne supplémentaire avec u = .. affectation? comment mettre la valeur u dans l'instruction for?

Je voudrais quelque chose de similaire à ci-dessous, mais en utilisant l'expression gen, pas la fonction:

yld123cu = (x * u for x in range(1, 4))

p >


2 commentaires

"id veut quelque chose de similaire à ci-dessous mais en utilisant l'expression gen, pas la fonction:" - pourquoi? C'est une solution parfaitement valable et fonctionnelle. Et dans les coulisses, il n'y a plus ou moins aucune différence entre les deux


merci les gars pour chaque réponse! appris quelque chose de chacun d'eux aujourd'hui. vraiment apprécié, site Web incroyable))


3 Réponses :


1
votes

Vous pouvez utiliser lambda . Cela fonctionne pour moi:

yld123cu = lambda u: (x * u for x in range(1, 4))

for i in yld123cu(2):
    print(i, end=' ')


3 commentaires

merci Uli, mais cela en fait toujours une fonction. J'étais plus intéressé à le garder comme un objet générateur et à toujours pouvoir lui passer des paramètres avec une syntaxe semblable à un appel de fonction


Un lambda nommé est considéré comme une mauvaise pratique par PEP8


Merci @ OlivierMelançon pour cet indice. +1



3
votes

Puisqu'une expression de générateur ne peut pas avoir sa propre portée, l'approche préférée serait de définir une fonction de générateur comme vous l'avez suggéré.

it = YieldReceive(yld123u(4))
for x in it:
    print(x)
    it.send(int(input('Enter next u value: ')))

Si vous devez mettre à jour u code > en cours de route et c'est la raison pour laquelle vous souhaitez éviter ce qui précède, sachez que vous pouvez envoyer une valeur à un générateur.

class YieldReceive:
    stop_iteration = object()

    def __init__(self, gen):
        self.gen = gen
        self.next = next(gen, self.stop_iteration)

    def __iter__(self):
        return self

    def __next__(self):
        if self.next is self.stop_iteration:
            raise StopIteration
        else:
            return self.next

    def send(self, value):
        try:
            self.next = self.gen.send(value)
        except StopIteration:
            self.next = self.stop_iteration

Exemples

Le générateur se comporte toujours de la même manière si vous n'utilisez pas send.

XXX

Sortie

4 0 12

Vous pouvez utiliser send pour mettre à jour la valeur de u .

gen = yld123u(4)
v0 = next(gen)
v1 = gen.send(0)
v2 = gen.send(4)
print(v0, v1, v2)

Sortie

4
8
12 

Boucle d'entrée

Si vous avez besoin du générateur pour interagir avec l'utilisateur entrée, voici une de mes réponses précédentes qui suggère un moyen d'implémenter un générateur de rendement-réception utilisable dans une boucle for .

for x in yld123u(4):
    print(x)

Utilisation

def yld123u(u):
    for i in range(1, 4):
        received = yield i * u # a sent value will be assigned to 'received'
        u = u if received is None else received


1 commentaires

salut Olivier, merci beaucoup pour la perspicacité et les détails fantastiques! et le lien pour la méthode d'envoi aussi. J'ai joué toute la journée avec le débogueur pycharm qui m'enveloppait la tête .. donc les fonctions gen + send / next sont la voie à suivre, okey. Je n'ai étudié le python que quelques semaines après la famille C, je viens juste de passer à la partie oop hier, alors j'ai vraiment apprécié de parcourir votre échantillon de classe. c'est un travail si noble que vous faites si généreusement en aidant les gens, tout le meilleur pour vous !!



1
votes

Vous pouvez essayer comme ça.

Remarque: Ici, nous n'avons pas de problème d'utilisation de la fonction lambda nommée.

2 4 6 

ou

for i in (lambda u: (x * u for x in range(1, 4)))(2): 
    print(i, end=' ')

»Sortie

for i in (lambda u: (x * u for x in range(1, 4)))(u=2): 
    print(i, end=' ')


0 commentaires