Heim  >  Artikel  >  Backend-Entwicklung  >  Einführung und Verwendung von Python-Generatoren

Einführung und Verwendung von Python-Generatoren

零下一度
零下一度Original
2017-07-19 23:25:521740Durchsuche

Der Generator in Python speichert den Algorithmus und der Wert wird nur dann berechnet, wenn der Wert wirklich benötigt wird. Es ist eine faule Bewertung.

Es gibt zwei Möglichkeiten, einen Generator zu erstellen.

Die erste Methode: Ändern Sie den [] eines Listengenerierungsausdrucks in (), um einen Generator zu erstellen:

>>> x für x im Bereich(10)]>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]>>> * x für x in range(10)) # Beachten Sie, dass nach dem Ändern von [] kein Tupel generiert wird, sondern ein gdb3e816b2012a27d795621f248f52dd3 >

Zweiter Weg: Verwenden Sie das Schlüsselwort yield in der Funktion, und die Funktion wird zu einem Generator.

Sobald die Funktion „Yield“ enthält, stoppt die Ausführung, wenn „Yield“ erreicht ist, und die Berechnung wird nur dann fortgesetzt, wenn weitere Berechnungen erforderlich sind. Es spielt also keine Rolle, selbst wenn die Generatorfunktion eine Endlosschleife hat, sie berechnet so viel, wie zum Zählen erforderlich ist, und zählt nicht weiter, wenn dies nicht erforderlich ist.

def fib():

a, b = 0, 1

while True:
yield a
a, b = b, a + b
f = fib()
print f, next(f), next(f), next(f)
# 8f3ab7789c38b631c1b219fec2271f37 0 1 1

Wie im obigen Beispiel ist f, wenn es zum ersten Mal ausgegeben wird, ein Generator, und jedes Mal, wenn es das nächste Mal ausgeführt wird, wird es ausgeführt, um a zu ergeben.

Natürlich wird next() selten verwendet. Wir können eine for-Schleife direkt verwenden, um einen Generator zu durchlaufen. Tatsächlich besteht die interne Implementierung der for-Schleife darin, next() kontinuierlich aufzurufen.

Der Generator kann unnötige Berechnungen vermeiden und die Leistung verbessern; außerdem spart er Platz und kann Endlosschleifen-Datenstrukturen realisieren.

Generator-Syntax

Generator-Ausdruck: Das Gleiche wie die Listen-Parsing-Syntax, aber ersetzen Sie das [] der Listen-Analyse durch ()
Generator-Ausdruck kann grundsätzlich mit der Listen-Analyse umgehen Dinge, aber wenn die zu verarbeitende Sequenz relativ groß ist, verbraucht die Listenanalyse mehr Speicher.


Generatorfunktion: Wenn das Schlüsselwort yield in einer Funktion vorkommt, ist die Funktion keine gewöhnliche Funktion mehr, sondern eine Generatorfunktion.

In Python ist yield ein solcher Generator.

Der Betriebsmechanismus des Ertragsgenerators:

Wenn Sie den Generator nach einer Zahl fragen, wird der Generator ausgeführt, bis die Ertragsangabe erscheint, und der Generator wird die Ihnen werden Parameter vorgegeben und der Generator läuft dann nicht weiter. Wenn Sie ihn nach der nächsten Nummer fragen, beginnt er mit dem letzten Bundesstaat. Beginnen Sie mit der Ausführung, bis die Yield-Anweisung angezeigt wird, geben Sie die Parameter ein und stoppen Sie dann. Dies wird wiederholt, bis die Funktion beendet wird.

Verwendung von yield:

Wenn Sie in Python eine Funktion definieren und das Schlüsselwort yield verwenden, ist die Funktion ein Generator und ihre Ausführung ist die gleiche wie bei anderen gewöhnlichen Funktionen Viele Unterschiede: Die Funktion gibt ein Objekt zurück, anstatt den Ergebniswert wie die normalerweise verwendete Return-Anweisung abzurufen. Wenn Sie den Wert erhalten möchten, müssen Sie die Funktion next() aufrufen

Nehmen Sie Fibonacci als Beispiel:

#coding:utf8
def fib(max): #10
    n, a, b = 0, 0, 1
    while n < max: #n<10
        #print(b)
        yield b
        a, b = b, a + b

        n += 1
    return 

f = fib(10)
for i in f:
    print f

Aus der obigen Beschreibung des Betriebsmechanismus können wir erkennen, dass das Programm nicht weiter ausgeführt wird, wenn es die Ertragsgrenze erreicht. Stattdessen wird ein Iterator

-Objekt zurückgegeben, das den -Status aller Parameter der aktuellen Funktion enthält. Der Zweck besteht darin, beim zweiten Aufruf auf alle Parameterwerte der Funktion auf die Werte beim ersten Zugriff zuzugreifen, anstatt Werte neu zuzuweisen. Beim ersten Aufruf des Programms:

程序第二次调用时:

从前面可知,第一次调用时,a,b=0,0,那么,我们第二次调用时(其实就是调用第一次返回的iterator对象的next()方法),程序跳到yield语句处,

执行a,b = b, a+b语句,此时值变为:a,b = 0, (0+1) => a,b = 0, 1

程序继续while循环,当然,再一次碰到了yield a 语句,也是像第一次那样,保存函数所有参数的状态,返回一个包含这些参数状态的iterator对象。

等待第三次的调用....

 

通过上面的分析,可以一次类推的展示了yield的详细运行过程了!

通过使用生成器的语法,可以免去写迭代器类的繁琐代码,如,上面的例子使用迭代类来实现,代码如下:

#coding:UTF8

class Fib:  
    def __init__(self, max):  
        self.max = max
        print self.max
    def __iter__(self):  
        self.a = 0  
        self.b = 1 
        self.n = 0 
        return self  
    def next(self):  
        fib = self.n  
        if fib >= self.max:  
            raise StopIteration  
        self.a, self.b = self.b, self.a + self.b  
        self.n += 1
        return self.a
    
f = Fib(10)
for i in f:
    print i

yield 与 return

在一个生成器中,如果没有return,则默认执行到函数完毕时返回StopIteration;

 

 如果遇到return,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代。

如果在return后返回一个值,会直接报错,生成器没有办法使用return来返回值。

 

生成器支持的方法(借鉴别人的例子,感觉蛮好的)

     close(...)
 |      close() -> raise GeneratorExit inside generator.
 |  
 |  next(...)
 |      x.next() -> the next value, or raise StopIteration
 |  
 |  send(...)
 |      send(arg) -> send &#39;arg&#39; into generator,
 |      return next yielded value or raise StopIteration.
 |  
 |  throw(...)
 |      throw(typ[,val[,tb]]) -> raise exception in generator,
 |      return next yielded value or raise StopIteration.

 

close()

手动关闭生成器函数,后面的调用会直接返回StopIteration异常。

#coding:UTF8

def fib():
    yield 1
    yield 2
    yield 3

f = fib()
print f.next()
f.close()
print f.next()

 

send()

生成器函数最大的特点是可以接受外部传入的一个变量,并根据变量内容计算结果后返回。
这是生成器函数最难理解的地方,也是最重要的地方,

def gen():
    value=0
    while True:
        receive=yield value
        if receive==&#39;e&#39;:
            break
        value = &#39;got: %s&#39; % receive
 
g=gen()
print(g.send(None))     
print(g.send(&#39;aaa&#39;))
print(g.send(3))
print(g.send(&#39;e&#39;))

执行流程:

  1. 通过g.send(None)或者next(g)可以启动生成器函数,并执行到第一个yield语句结束的位置。此时,执行完了yield语句,但是没有给receive赋值。yield value会输出初始值0注意:在启动生成器函数时只能send(None),如果试图输入其它的值都会得到错误提示信息。

  2. 通过g.send(‘aaa’),会传入aaa,并赋值给receive,然后计算出value的值,并回到while头部,执行yield value语句有停止。此时yield value会输出”got: aaa”,然后挂起。

  3. 通过g.send(3),会重复第2步,最后输出结果为”got: 3″

  4. 当我们g.send(‘e’)时,程序会执行break然后推出循环,最后整个函数执行完毕,所以会得到StopIteration异常。

最后的执行结果如下:

0
got: aaa
got: 3
Traceback (most recent call last):
  File "1.py", line 15, in <module>
    print(g.send(&#39;e&#39;))
StopIteration

 

throw()

用来向生成器函数送入一个异常,可以结束系统定义的异常,或者自定义的异常。
throw()后直接跑出异常并结束程序,或者消耗掉一个yield,或者在没有下一个yield的时候直接进行到程序的结尾。

def gen():
    while True: 
        try:
            yield &#39;normal value&#39;
            yield &#39;normal value 2&#39;
            print(&#39;here&#39;)
        except ValueError:
            print(&#39;we got ValueError here&#39;)
        except TypeError:
            break
 
g=gen()
print(next(g))
print(g.throw(ValueError))
print(next(g))
print(g.throw(TypeError))

执行流程:

  1. print(next(g)):会输出normal value,并停留在yield ‘normal value 2’之前。

  2. 由于执行了g.throw(ValueError),所以会跳过所有后续的try语句,也就是说yield ‘normal value 2’不会被执行,然后进入到except语句,打印出we got ValueError here。然后再次进入到while语句部分,消耗一个yield,所以会输出normal value。

  3. print(next(g)),会执行yield ‘normal value 2’语句,并停留在执行完该语句后的位置。

  4. g.throw(TypeError):会跳出try语句,从而print(‘here’)不会被执行,然后执行break语句,跳出while循环,然后到达程序结尾,所以跑出StopIteration异常。

  

 

Das obige ist der detaillierte Inhalt vonEinführung und Verwendung von Python-Generatoren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn