12901 Stimmen

Was bewirkt das Schlüsselwort "yield"?

Wozu dient die yield Schlüsselwort in Python? Was bewirkt es?

Ich versuche zum Beispiel, folgenden Code zu verstehen 1 :

def _get_child_candidates(self, distance, min_dist, max_dist):
    if self._leftchild and distance - max_dist < self._median:
        yield self._leftchild
    if self._rightchild and distance + max_dist >= self._median:
        yield self._rightchild  

Und das ist der Anrufer:

result, candidates = [], [self]
while candidates:
    node = candidates.pop()
    distance = node._get_dist(obj)
    if distance <= max_dist and distance >= min_dist:
        result.extend(node._values)
    candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result

Was passiert, wenn die Methode _get_child_candidates aufgerufen wird? Wird eine Liste zurückgegeben? Ein einzelnes Element? Wird sie erneut aufgerufen? Wann werden die nachfolgenden Aufrufe beendet?


1. Dieses Stück Code wurde von Jochen Schulz (jrschulz) geschrieben, der eine großartige Python-Bibliothek für metrische Räume entwickelt hat. Dies ist der Link zum vollständigen Quellcode: <a href="https://well-adjusted.de/~jrspieker/mspace/" rel="noreferrer">Modul mspace </a>.

17voto

yash bhangare Punkte 53

Le site yield Schlüsselwort in Python verwendet, um den Code zu verlassen, ohne den Zustand der lokalen Variablen zu stören, und wenn die Funktion erneut aufgerufen wird, beginnt die Ausführung an dem letzten Punkt, an dem wir den Code verlassen haben.

Das folgende Beispiel demonstriert die Funktionsweise von yield :

def counter():
    x=2
    while x < 5:
        yield x
        x += 1

print("Initial value of x: ", counter()) 

x=2
x=x+1

for y in counter():
    print(y)

Der obige Code erzeugt die unten stehende Ausgabe:

Initial value of x:  <generator object counter at 0x7f0263020ac0>
2
3
4

16voto

Aaron_ab Punkte 3066

Kann auch Daten an den Generator zurücksenden!

Wie in vielen Antworten erläutert, ist die Verwendung von yield erstellt eine generator .

Sie können die yield Schlüsselwort zu Daten an einen "lebenden" Generator zurücksenden .

Beispiel:

Nehmen wir an, wir haben eine Methode, die von Englisch in eine andere Sprache übersetzt. Und am Anfang macht sie etwas, das schwer ist und nur einmal gemacht werden sollte. Wir wollen, dass diese Methode für immer läuft (weiß nicht wirklich, warum :)), und erhalten Wörter Wörter übersetzt werden.

def translator():
    # load all the words in English language and the translation to 'other lang'
    my_words_dict = {'hello': 'hello in other language', 'dog': 'dog in other language'}

    while True:
        word = (yield)
        yield my_words_dict.get(word, 'Unknown word...')

Laufen:

my_words_translator = translator()

next(my_words_translator)
print(my_words_translator.send('dog'))

next(my_words_translator)
print(my_words_translator.send('cat'))

wird gedruckt:

dog in other language
Unknown word...

Zusammengefasst:

verwenden. send Methode innerhalb eines Generators, um Daten zurück an den Generator zu senden. Um dies zu ermöglichen, muss eine (yield) verwendet wird.

12voto

Swati Srivastava Punkte 982

Yield in Python ist in gewisser Weise ähnlich wie die return-Anweisung, mit Ausnahme einiger Unterschiede. Wenn mehrere Werte von einer Funktion zurückgegeben werden müssen, gibt die return-Anweisung alle Werte in Form einer Liste zurück, die im Speicher des Aufruferblocks abgelegt werden muss. Was aber, wenn wir keinen zusätzlichen Speicher verwenden wollen? Stattdessen wollen wir den Wert aus der Funktion abrufen, wenn wir ihn brauchen. Hier kommt yield ins Spiel. Betrachten wir die folgende Funktion :-

def fun():
   yield 1
   yield 2
   yield 3

Und der Anrufer ist :-

def caller():
   print ('First value printing')
   print (fun())
   print ('Second value printing')
   print (fun())
   print ('Third value printing')
   print (fun())

Das obige Codesegment (Aufruferfunktion) gibt beim Aufruf :-

First value printing
1
Second value printing
2
Third value printing
3

Wie oben zu sehen ist, gibt yield einen Wert an seinen Aufrufer zurück, aber wenn die Funktion erneut aufgerufen wird, beginnt sie nicht mit der ersten Anweisung, sondern mit der Anweisung direkt nach yield. Im obigen Beispiel wurde "First value printing" gedruckt und die Funktion wurde aufgerufen. Es wurde 1 zurückgegeben und gedruckt. Dann wurde "Zweiter Wert drucken" gedruckt und wieder fun() aufgerufen. Anstatt 1 (die erste Anweisung) zu drucken, wurde 2 zurückgegeben, d. h. die Anweisung direkt nach yield 1. Der gleiche Vorgang wird weiter wiederholt.

9voto

ToTamire Punkte 783

Einfache Antwort

Wenn die Funktion mindestens eine yield Anweisung wird die Funktion automatisch zur Generatorfunktion. Wenn Sie eine Generatorfunktion aufrufen, führt Python den Code in der Generatorfunktion aus, bis yield Anweisung auftreten. yield Anweisung friert die Funktion mit all ihren internen Zuständen ein. Wenn Sie die Generatorfunktion erneut aufrufen, setzt Python die Ausführung des Codes in der Generatorfunktion ab der eingefrorenen Position fort, bis yield Aussage immer wieder vorkommen. Die Generatorfunktion führt den Code aus, bis die Generatorfunktion abläuft, ohne yield Erklärung.

Benchmark

Erstellen Sie eine Liste und geben Sie sie zurück:

def my_range(n):
    my_list = []
    i = 0
    while i < n:
        my_list.append(i)
        i += 1
    return my_list

@profile
def function():
    my_sum = 0
    my_values = my_range(1000000)
    for my_value in my_values:
        my_sum += my_value

function()

Ergebnisse mit:

Total time: 1.07901 s
Timer unit: 1e-06 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     9                                           @profile
    10                                           def function():
    11         1          1.1      1.1      0.0      my_sum = 0
    12         1     494875.0 494875.0     45.9      my_values = my_range(1000000)
    13   1000001     262842.1      0.3     24.4      for my_value in my_values:
    14   1000000     321289.8      0.3     29.8          my_sum += my_value

Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
     9   40.168 MiB   40.168 MiB           1   @profile
    10                                         def function():
    11   40.168 MiB    0.000 MiB           1       my_sum = 0
    12   78.914 MiB   38.746 MiB           1       my_values = my_range(1000000)
    13   78.941 MiB    0.012 MiB     1000001       for my_value in my_values:
    14   78.941 MiB    0.016 MiB     1000000           my_sum += my_value

Erzeugen Sie Werte im laufenden Betrieb:

def my_range(n):
    i = 0
    while i < n:
        yield i
        i += 1

@profile
def function():
    my_sum = 0

    for my_value in my_range(1000000):
        my_sum += my_value

function()

Ergebnisse mit:

Total time: 1.24841 s
Timer unit: 1e-06 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     7                                           @profile
     8                                           def function():
     9         1          1.1      1.1      0.0      my_sum = 0
    10
    11   1000001     895617.3      0.9     71.7      for my_value in my_range(1000000):
    12   1000000     352793.7      0.4     28.3          my_sum += my_value

Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
     7   40.168 MiB   40.168 MiB           1   @profile
     8                                         def function():
     9   40.168 MiB    0.000 MiB           1       my_sum = 0
    10
    11   40.203 MiB    0.016 MiB     1000001       for my_value in my_range(1000000):
    12   40.203 MiB    0.020 MiB     1000000           my_sum += my_value

Zusammenfassung

Die Generatorfunktion benötigt etwas mehr Zeit für die Ausführung als eine Funktion, die eine Liste zurückgibt, aber sie verbraucht viel weniger Speicher.

8voto

Ted Shaneyfelt Punkte 635

Ein einfacher Anwendungsfall:

>>> def foo():
    yield 100
    yield 20
    yield 3

>>> for i in foo(): print(i)

100
20
3
>>> 

Funktionsweise: Wenn die Funktion aufgerufen wird, gibt sie sofort ein Objekt zurück. Das Objekt kann an die Funktion next() übergeben werden. Jedes Mal, wenn die next()-Funktion aufgerufen wird, läuft Ihre Funktion bis zum nächsten Ertrag und liefert den Rückgabewert für die next()-Funktion.

Unter der Haube erkennt die for-Schleife, dass es sich bei dem Objekt um ein Generatorobjekt handelt und verwendet next(), um den nächsten Wert zu erhalten.

In einigen Sprachen wie ES6 und höher ist es ein wenig anders implementiert, so dass next eine Mitgliedsfunktion des Generatorobjekts ist und Sie jedes Mal Werte vom Aufrufer übergeben können, wenn er den nächsten Wert erhält. Wenn also result der Generator ist, könnten Sie etwas tun wie y = result.next(555), und das Programm, das Werte liefert, könnte etwas sagen wie z = yield 999. Der Wert von y wäre 999, den next von yield erhält, und der Wert von z wäre 555, den yield von next erhält. Die Python-Methoden get und send haben einen ähnlichen Effekt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X