2017-08-26 9 views
2

que je suis en train de convertir le code Ruby au code Python et maintenant je suis coincé avec cette fonction qui contient yield:Rendement en Python (migration à partir de Ruby): Comment écrire une fonction sans argument et uniquement avec yield to do prints?

def three_print(): 
    yield 
    yield 
    yield 

Je voudrais appeler la fonction et lui dire d'imprimer « Bonjour » trois fois parce que des trois instructions yield. Comme la fonction ne prend aucun argument, j'obtiens une erreur. Pouvez-vous me dire le moyen le plus facile de le faire fonctionner? Je vous remercie.

+0

Autre que l'ajout d'un argument? –

+4

Notez que le mot-clé 'yield' dans Ruby a un comportement très différent du mot-clé' yield' dans Python. –

+1

** Note aux réponses potentielles: ** Veuillez lire attentivement la question. L'OP cherche à traduire le code avec une sémantique spécifique de ruby ​​à Python. Tandis que les réponses comme 'print ('Hello \ n' * 3)' sont techniquement correctes, elles manquent le point le plus important: Le comportement du mot-clé 'yield' dans Ruby vs Python. –

Répondre

7

yield en Ruby et yield en Python sont deux choses très différentes.

En Ruby yield exécute un bloc transmis en tant que paramètre à la fonction.

Ruby:

def three 
    yield 
    yield 
    yield 
end 

three { puts 'hello '} # runs block (prints "hello") three times 

En Python yield jette une valeur à partir d'un générateur (qui est une fonction qui utilise yield) et arrête l'exécution de la fonction. Donc, c'est quelque chose de complètement différent, plus probablement vous voulez passer une fonction en paramètre à la fonction en Python.

Python:

def three(func): 
    func() 
    func() 
    func() 

three(lambda: print('hello')) # runs function (prints "hello") three times 

Générateurs Python

Le code ci-dessous (le code que vous avez fourni) est un générateur qui retourne None trois fois:

def three(): 
    yield 
    yield 
    yield 

g = three() #=> <generator object three at 0x7fa3e31cb0a0> 
next(g) #=> None 
next(g) #=> None 
next(g) #=> None 
next(g) #=> StopIteration 

La seule façon que je peux imaginer comment il pourrait être utilisé pour l'impression "Bonjour" trois fois - en l'utilisant comme un itérateur:

for _ in three(): 
    print('Hello') 

Ruby Analogie

Vous pouvez faire une chose semblable à Ruby en utilisant Enumerator.new:

def three 
    Enumerator.new do |e| 
    e.yield # or e << nil 
    e.yield # or e << nil 
    e.yield # or e << nil 
    end 
end 

g = three 
g.next #=> nil 
g.next #=> nil 
g.next #=> nil 
g.next #=> StopIteration 

three.each do 
    puts 'Hello' 
end 
+0

Vous devriez mentionner que l'équivalent Ruby au [mot-clé ** yield ** de Python **] (https://docs.python.org/3.7/reference/expressions.html#yieldexpr) est le [Ruby 'Enumerator :: Yielder # yield' ** méthode **] (http://ruby-doc.org/core/Enumerator.html#method-c-new) (également aliasé 'Enumerator :: Yielder # <<', et ni l'un ni l'autre correctement documenté, malheureusement). –

+0

@ JörgWMittag merci pour l'avis, je l'ai ajouté à la réponse –

0

Vous pouvez produire dans une boucle:

def hello(): 
    for i in range(3): 
     yield "hello" 

print(list(hello())) 

Sortie:

['hello', 'hello', 'hello'] 

En Python3.3 et plus, vous pouvez utiliser l'instruction yield from:

def hello(): 
    yield from ["hello" for i in range(3)] 

print(list(hello())) 

sortie:

['hello', 'hello', 'hello'] 
+0

Nitpick mineur: La syntaxe 'yield from' n'est disponible que dans Python _3.3_ et supérieur. Voir [ici] (https://www.python.org/dev/peps/pep-0380/). –

+0

@ChristianDean Merci! Je ne le savais pas. Fixé maintenant – Ajax1234

+0

_Eh_, toujours pas exactement correct. C'est seulement disponible en Python 3.3 et supérieur. Toute version de Python 3.x ne fonctionnera pas. Il doit spécifiquement être Python 3.3+. –

0
def three_print(): 
    yield("Hello") 
    yield("Hello") 
    yield("Hello") 

car il y a trois yields, vous devez appeler three_print().next() trois fois pour obtenir la chaîne "Hello" à la sortie

7

yield en Python ne fonctionne pas comme dans Ruby. En particulier, cela ne signifie pas "exécuter l'argument du bloc ici". Cette fonction n'exécutera jamais de rappels.

En Python, yield permet de créer des itérateurs (en particulier des générateurs), et la fonction que vous avez publiée renvoie un itérateur qui produit None 3 fois. Vous pouvez passer en boucle la iterator et print « Bonjour » pour chaque valeur, ignorant la None:

for _ in three_print(): 
    print("Hello") 

qui est le plus proche vous obtiendrez le comportement Ruby, mais fondamentalement différent en termes de mécanismes sous-jacents.

Sinon, si vous ne veulent une fonction qui exécute un rappel 3 fois, ce serait

def f(callback): 
    callback() 
    callback() 
    callback() 

et vous pourriez l'appeler comme

f(lambda: print("Hello")) 
1

Vous pouvez utiliser:

def three_print(): 
    yield"Hello\n"*3 
print(''.join(list(three_print()))) 

# Hello 
# Hello 
# Hello