>백엔드 개발 >파이썬 튜토리얼 >한 기사에서 Python 생성기에 대한 자세한 설명

한 기사에서 Python 생성기에 대한 자세한 설명

WBOY
WBOY앞으로
2022-06-09 16:02:172696검색

이 글은 제너레이터의 개념, 제너레이터의 실행 프로세스, 수율 및 제너레이터 방법 등 제너레이터와 관련된 문제를 주로 소개하는 python에 대한 관련 지식을 제공합니다. 모두에게 도움이 될 것입니다.

한 기사에서 Python 생성기에 대한 자세한 설명

추천 학습: python 동영상 튜토리얼

이 기사는 Python에 대한 관련 지식을 제공하며, 발전기의 개념과 기능을 포함하여 발전기와 관련된 문제를 주로 소개합니다. 실행 프로세스를 살펴보겠습니다. , Yield 및 Generator 방법 등이 모두에게 도움이 되기를 바랍니다.

1. 생성기 개념

Generator(영어: 생성기)는 매우 흥미로운 것이며 종종 Python에서 고급 프로그래밍 기술로 간주됩니다. 그러나 비록 당신이 초보자일지라도 나는 여전히 독자들과 이 주제에 대해 토론하게 되어 기쁩니다. 왜냐하면 나는 이 튜토리얼을 읽는 목적이 당신 자신을 초급 수준으로 제한하는 것이 아니라고 믿기 때문입니다. 파이썬 마스터가 되세요. 그럼 발전기에 대해 알아보겠습니다.

이전 섹션의 "반복자"를 기억하시나요? 생성기와 반복기는 특정 원점 관계를 갖습니다. Generator는 Iterable이어야 합니다. 단순한 Iterator가 아닌 것은 사실이지만 그 외에는 다른 용도가 많지 않으므로 매우 편리한 Custom Iterator로 이해할 수 있습니다.

2. 단순 생성기

>>> my_generator = (x*x for x in range(4))

이것은 목록 이해와 매우 유사합니까? 잘 관찰해 보면 목록이 아닙니다. 이렇게 얻으면 목록입니다.

>>> my_list = [x*x for x in range(4)]

위 둘의 차이는 [] 또는 ()이지만, 결과는 완전히 다릅니다.

>>> dir(my_generator)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__',
'__iter__',
'__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running',
'next',
'send', 'throw']

쉽게 관찰하기 위해 위 결과를 다시 정리했습니다. 반복자에서 필요한 메서드 __inter__() 및 next()를 발견했습니까? 이는 반복자임을 보여줍니다. Iterator인 경우 for 루프를 사용하여 해당 값을 순서대로 읽을 수 있습니다

>>> for i in my_generator:
... print i
...
0
1
4
9
>>> for i in my_generator:
... print i
...

처음 루프를 돌릴 때는 my_generator의 값을 순서대로 읽어서 인쇄합니다. 다시 읽어보면 아무런 결과도 없다는 것을 알게 됩니다. 이 기능은 반복자에도 있습니다.

해당 목록의 경우에는 다릅니다.

>>> for i in my_list:
... print i
...
0
1
4
9
>>> for i in my_list:
... print i
...
0
1
4
9

생성기가 목록 구문 분석에서 []를 ()로 바꾸는 것일 수 있습니까? 이것은 단지 생성자의 표현 및 사용법의 한 형태일 뿐입니다.

리스트 컴프리헨션의 이름을 따서 "생성기 분석 표현"(또는: 생성기 파생, 생성기 표현)이라고 부를 수 있습니다.

생성기 구문 분석 표현식은 다양한 용도로 사용되며 여러 위치에서 목록을 대체하는 데 좋은 선택입니다. 특히 이전 섹션에서 언급한 것처럼 많은 수의 값을 처리할 때 목록은 더 많은 메모리를 차지합니다. 반복자(생성자는 반복자임)의 장점은 메모리를 적게 차지하므로 생성자(또는 반복자)를 인스턴스화할 필요가 없다는 것입니다. ) 리스트로 변환하여 직접 연산하여 iteration의 장점을 보여줍니다. 예:

>>> sum(i*i for i in range(10))
285

위의 sum() 연산에 주의하세요. 괄호가 빠졌다고 생각하지 마세요. 그냥 이렇게 쓰여 있습니다. 매력적이지 않나요? 목록에 있는 경우 다음을 수행해야 합니다.

>>> sum([i*i for i in range(10)])
285

발전기 분석을 통해 얻은 발전기에는 발전기의 일부 세부 정보가 포함되어 있으며 적용 가능한 영역이 제한되어 있습니다. 다음으로, 발전기의 내부를 분석하고 이 마법 도구에 대해 더 깊이 이해해 보겠습니다.

3. 정의 및 실행 과정

yield는 중국어로 "생산, 생산"이라는 뜻으로 파이썬에서는 키워드로 사용됩니다(변수, 함수, 클래스 이름에는 사용할 수 없습니다

). 발전기의 상징.

>>> def g():
... yield 0
... yield 1
... yield 2
...
>>> g
<function g at 0xb71f3b8c>

는 매우 간단한 함수를 만들었습니다. 이전에 본 함수와 유일한 차이점은 세 개의 항복 문을 사용한다는 것입니다. 그런 다음 다음 작업을 수행합니다.

>>> ge = g()
>>> ge
<generator object g at 0xb7200edc>
>>> type(ge)
<type &#39;generator&#39;>

위에서 설정한 함수의 반환 값은 생성기 유형의 개체입니다.

>>> dir(ge)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']

여기에서 __iter__() 및 next()가 반복자임을 나타내는 것을 보았습니다. 이 경우는 물론입니다.

>>> ge.next()
0
>>> ge.next()
1
>>> ge.next()
2
>>> ge.next()
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
StopIteration

이 간단한 예를 통해 Yield 키워드가 포함된 함수의 반환 값이 생성기 유형 개체이고 이 생성기 개체가 반복자임을 알 수 있습니다.

Yield 문 생성기가 포함된 함수를 호출합니다. 생성기는 일반 함수 구문으로 정의된 반복자입니다. 위의 예에서 볼 수 있듯이 이 생성기(반복자이기도 함)의 정의 프로세스 중에 __inter__() 및 next()는 이전 섹션의 반복자처럼 작성되지 않습니다. 대신, Yield 문이 사용됩니다. , 일반 함수 마법처럼 생성기가 되며 반복자의 기능적 특성을 갖습니다.

yield 문의 기능은 호출 시 해당 값을 반환하는 것입니다. 위의 실행 프로세스를 자세히 분석해 보겠습니다.

1.ge = g(): 생성기를 반환하는 것 외에는 아무런 작업도 없고 값도 반환되지 않습니다.

2.ge.next(): 이 시점까지는 생성기가 실행을 시작하지 않습니다. 첫 번째 항복 문을 만나면 값을 반환하고 실행을 일시 중지합니다(일부에서는 이를

이라고도 함).

为挂起)。

3. ge.next() :从上次暂停的位置开始,继续向下执行,遇到 yield 语句,将值返回,又暂停。

4. gen.next() :重复上面的操作。

5. gene.next() :从上面的挂起位置开始,但是后面没有可执行的了,于是 next() 发出异常。

从上面的执行过程中,发现 yield 除了作为生成器的标志之外,还有一个功能就是返回值。那么它跟 return 这个返回值有什么区别呢?

4. yield

为了弄清楚 yield 和 return 的区别,我写了两个函数来掩饰:

>>> def r_return(n):
... print "You taked me."
... while n > 0:
... print "before return"
... return n
... n -= 1
... print "after return"
...
>>> rr = r_return(3)
You taked me.
before return
>>> rr
3

从函数被调用的过程可以清晰看出, rr = r_return(3) ,函数体内的语句就开始执行了,遇到 return,将值返

回,然后就结束函数体内的执行。所以 return 后面的语句根本没有执行。这是 return 的特点

下面将 return 改为 yield:

>>> def y_yield(n):
... print "You taked me."
... while n > 0:
...     print "before yield"
...     yield n
...     n -= 1
...     print "after yield"
...
>>> yy = y_yield(3) #没有执行函数体内语句
>>> yy.next() #开始执行
You taked me.
before yield
3 #遇到 yield,返回值,并暂停
>>> yy.next() #从上次暂停位置开始继续执行
after yield
before yield
2 #又遇到 yield,返回值,并暂停
>>> yy.next() #重复上述过程
after yield
before yield
1
>>> yy.next()
after yield #没有满足条件的值,抛出异常
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
StopIteration

结合注释和前面对执行过程的分析,读者一定能理解 yield 的特点了,也深知与 return 的区别了。

一般的函数,都是止于 return。作为生成器的函数,由于有了 yield,则会遇到它挂起,如果还有 return,遇到它就直接抛出 SoptIteration 异常而中止迭代。

#!/usr/bin/env Python
# coding=utf-8

def fibs(max):
    """
    斐波那契数列的生成器
    """
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
if __name__ == "__main__":
    f = fibs(10)
    for i in f:
        print i ,

运行结果如下:

$ python 21501.py
1 1 2 3 5 8 13 21 34 55

用生成器方式实现的斐波那契数列是不是跟以前的有所不同了呢?大家可以将本教程中已经演示过的斐波那契数列实现方式做一下对比,体会各种方法的差异。

经过上面的各种例子,已经明确,一个函数中,只要包含了 yield 语句,它就是生成器,也是迭代器。这种方式显然比前面写迭代器的类要简便多了。但,并不意味着上节的就被抛弃。是生成器还是迭代器,都是根据具体的使用情景而定。

5. 生成器方法

在 python2.5 以后,生成器有了一个新特征,就是在开始运行后能够为生成器提供新的值。这就好似生成器

和“外界”之间进行数据交流。

>>> def repeater(n):
... while True:
...     n = (yield n)
...
>>> r = repeater(4)
>>> r.next()
4
>>> r.send("hello")
'hello

当执行到 r.next() 的时候,生成器开始执行,在内部遇到了 yield n 挂起。注意在生成器函数中, n = (yield

n) 中的 yield n 是一个表达式,并将结果赋值给 n,虽然不严格要求它必须用圆括号包裹,但是一般情况都这

么做,请大家也追随这个习惯。

当执行 r.send("hello") 的时候,原来已经被挂起的生成器(函数)又被唤醒,开始执行 n = (yield n) ,也就是

讲 send() 方法发送的值返回。这就是在运行后能够为生成器提供值的含义。

如果接下来再执行 r.next() 会怎样?

>>> r.next()

什么也没有,其实就是返回了 None。按照前面的叙述,读者可以看到,这次执行 r.next() ,由于没有传入任何值,yield 返回的就只能是 None.

还要注意,send() 方法必须在生成器运行后并挂起才能使用,也就是 yield 至少被执行一次。如果不是这样:

>>> s = repeater(5)
>>> s.send("how")
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
TypeError: can't send non-None value to a just-started generator

就报错了。但是,可将参数设为 None:

>>> s.send(None)
5

这是返回的是调用函数的时传入的值。

此外,还有两个方法:close() 和 throw()

• throw(type, value=None, traceback=None):用于在生成器内部(生成器的当前挂起处,或未启动时在定

义处)抛出一个异常(在 yield 表达式中)。

• close():调用时不用参数,用于关闭生成器。

推荐学习:python视频教程

위 내용은 한 기사에서 Python 생성기에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제