[python] 파이썬 생성기 함수를 무엇에 사용할 수 있습니까?

나는 파이썬을 배우기 시작했고 생성 함수, yield 문이있는 함수를 발견했습니다. 이러한 기능이 실제로 해결하는 데 어떤 유형의 문제가 있는지 알고 싶습니다.



답변

발전기는 게으른 평가를 제공합니다. ‘for’를 사용하여 명시 적으로 또는 암시 적으로 반복하여 함수 또는 반복 구조로 전달하여 사용합니다. 생성기는 마치 목록을 반환하는 것처럼 여러 항목을 반환하는 것으로 생각할 수 있지만 한 번에 하나씩 반환하는 대신 하나씩 반환하며 생성기 기능은 다음 항목이 요청 될 때까지 일시 중지됩니다.

생성기는 모든 결과가 필요한지 또는 모든 결과에 대해 동시에 메모리를 할당하지 않으려는 경우 큰 결과 세트 (특히 루프 자체를 포함하는 계산)를 계산하는 데 유용합니다. . 또는 생성기가 다른 생성기를 사용 하거나 다른 리소스를 사용하는 상황에서 가능한 한 늦게 발생하면 더 편리합니다.

생성기 (실제로 동일)의 또 다른 용도는 콜백을 반복으로 바꾸는 것입니다. 어떤 상황에서는 함수가 많은 작업을 수행하고 때로는 호출자에게 다시보고하기를 원합니다. 일반적으로 콜백 함수를 사용합니다. 이 콜백을 작업 기능에 전달하면 주기적으로이 콜백을 호출합니다. 생성기 접근 방식은 일 함수 (현재 생성기)가 콜백에 대해 아무것도 알지 못하고보고 할 때마다 생성하는 것입니다. 호출자는 별도의 콜백을 작성하고이를 작업 기능에 전달하는 대신 모든보고 작업을 생성기 주변의 작은 ‘for’루프로 수행합니다.

예를 들어, ‘파일 시스템 검색’프로그램을 작성했다고 가정하십시오. 전체 검색을 수행하고 결과를 수집 한 다음 한 번에 하나씩 표시 할 수 있습니다. 첫 번째 결과를 보여주기 전에 모든 결과를 수집해야하며 모든 결과는 동시에 메모리에 저장됩니다. 또는 결과를 찾는 동안 결과를 표시 할 수 있으며, 이는 메모리 효율성이 높고 사용자에게 훨씬 친숙합니다. 후자는 결과 인쇄 기능을 파일 시스템 검색 기능에 전달하여 수행하거나 검색 기능을 생성기로 만들고 결과를 반복하여 수행 할 수 있습니다.

후자의 두 가지 접근 방식의 예를 보려면 os.path.walk () (콜백이있는 기존 파일 시스템 워킹 함수) 및 os.walk () (새로운 파일 시스템 워킹 생성기)를 참조하십시오. 당신은 정말로 모든 결과를리스트로 수집하고 싶었습니다. 제너레이터 접근법은 큰리스트 접근법으로 변환하기가 쉽지 않습니다 :

big_list = list(the_generator)


답변

generator를 사용하는 이유 중 하나는 솔루션을 좀 더 명확하게하기위한 것입니다.

다른 하나는 결과를 한 번에 하나씩 처리하여 처리 할 결과 목록을 크게 만들지 않는 것입니다.

다음과 같은 피보나치-업 -n 기능이있는 경우 :

# function version
def fibon(n):
    a = b = 1
    result = []
    for i in xrange(n):
        result.append(a)
        a, b = b, a + b
    return result

다음과 같이 함수를보다 쉽게 ​​작성할 수 있습니다.

# generator version
def fibon(n):
    a = b = 1
    for i in xrange(n):
        yield a
        a, b = b, a + b

기능이 더 명확합니다. 그리고이 기능을 사용하면 :

for x in fibon(1000000):
    print x,

이 예제에서 생성기 버전을 사용하는 경우 전체 1000000 항목 목록이 전혀 작성되지 않고 한 번에 하나의 값만 작성됩니다. 목록 버전을 사용할 때는 목록이 먼저 생성되는 경우에는 해당되지 않습니다.


답변

PEP 255 의 “동기화”섹션을 참조하십시오 .

명백하게 생성기를 사용하는 것은 인터럽트 가능한 기능을 생성하여 스레드 업데이트를 사용하지 않고 UI를 업데이트하거나 여러 작업을 “동시”(실제로 인터리브)하는 등의 작업을 수행 할 수 있습니다.


답변

나는 의심의 여지가없는이 설명을 발견한다. 모르는 사람 Generators도 모르는 가능성이 있기 때문에yield

반환

return 문은 모든 로컬 변수가 파괴되고 결과 값이 호출자에게 반환 (반환)되는 곳입니다. 나중에 같은 함수를 호출하면 함수에 새로운 변수 세트가 새로 생깁니다.

수율

그러나 함수를 종료 할 때 지역 변수가 버려지지 않으면 어떻게 될까요? 이것은 우리가 멈출 수 resume the function있는 곳을 의미합니다 . 여기에서 개념 generators이 소개되고 중단 된 yield부분부터 문이 다시 시작됩니다 function.

  def generate_integers(N):
    for i in xrange(N):
    yield i

    In [1]: gen = generate_integers(3)
    In [2]: gen
    <generator object at 0x8117f90>
    In [3]: gen.next()
    0
    In [4]: gen.next()
    1
    In [5]: gen.next()

이것이 파이썬에서 returnyield문장 의 차이점 입니다.

항복 진술은 함수를 생성기 함수로 만드는 것입니다.

따라서 생성기는 반복자를 작성하기위한 간단하고 강력한 도구입니다. 일반 함수처럼 작성되지만 yield데이터를 리턴 할 때마다 명령문 을 사용합니다 . next ()가 호출 될 때마다 생성기는 중단 된 위치에서 재개합니다 (모든 데이터 값과 마지막으로 실행 된 명령문을 기억합니다).


답변

실제 예

MySQL 테이블에 1 억 개의 도메인이 있고 각 도메인의 Alexa 순위를 업데이트하려고한다고 가정하겠습니다.

가장 먼저 필요한 것은 데이터베이스에서 도메인 이름을 선택하는 것입니다.

테이블 이름이 domains있고 열 이름이 있다고 가정 해 봅시다.domain 입니다.

사용 SELECT domain FROM domains하면 많은 메모리를 소비하는 1 억 개의 행을 반환합니다. 따라서 서버가 중단 될 수 있습니다.

따라서 프로그램을 일괄 적으로 실행하기로 결정했습니다. 배치 크기가 1000이라고 가정 해 봅시다.

첫 번째 배치에서 첫 1000 행을 쿼리하고 각 도메인의 Alexa 순위를 확인하고 데이터베이스 행을 업데이트합니다.

두 번째 배치에서는 다음 1000 행에 대해 작업합니다. 세 번째 배치에서는 2001 년에서 3000 년 사이가됩니다.

이제 배치를 생성하는 생성기 함수가 필요합니다.

다음은 생성기 함수입니다.

def ResultGenerator(cursor, batchsize=1000):
    while True:
        results = cursor.fetchmany(batchsize)
        if not results:
            break
        for result in results:
            yield result

보시다시피, 우리의 기능 yield은 결과를 계속 유지 합니다. return대신 키워드를 사용하면 yield반환에 도달하면 전체 함수가 종료됩니다.

return - returns only once
yield - returns multiple times

함수가 키워드를 사용하는 경우 yield 를 생성기입니다.

이제 다음과 같이 반복 할 수 있습니다.

db = MySQLdb.connect(host="localhost", user="root", passwd="root", db="domains")
cursor = db.cursor()
cursor.execute("SELECT domain FROM domains")
for result in ResultGenerator(cursor):
    doSomethingWith(result)
db.close()


답변

버퍼링. 큰 청크로 데이터를 가져 오는 것이 효율적이지만 작은 청크로 처리하는 경우 생성기가 도움이 될 수 있습니다.

def bufferedFetch():
  while True:
     buffer = getBigChunkOfData()
     # insert some code to break on 'end of data'
     for i in buffer:
          yield i

위와 같이하면 버퍼링과 처리를 쉽게 분리 할 수 ​​있습니다. 소비자 함수는 이제 버퍼링에 대해 걱정할 필요없이 하나씩 값을 얻을 수 있습니다.


답변

생성기가 코드를 정리하고 코드를 캡슐화하고 모듈화 할 수있는 매우 독특한 방법을 제공함으로써 매우 유용한 것으로 나타났습니다. 자체 내부 처리를 기반으로 지속적으로 값을 내뱉을 무언가가 필요한 상황에서 코드의 어느 곳에서나 (예를 들어 루프 또는 블록 내에서) 무언가를 호출 해야하는 경우 생성기는 다음같은 기능입니다. 사용하다.

추상적 인 예는 루프 내에 존재하지 않는 피보나치 수 생성기이며, 어디서나 호출 될 때 항상 다음 번호를 순서대로 반환합니다.

def fib():
    first = 0
    second = 1
    yield first
    yield second

    while 1:
        next = first + second
        yield next
        first = second
        second = next

fibgen1 = fib()
fibgen2 = fib()

이제 코드의 어느 곳에서나 호출 할 수있는 두 개의 피보나치 수 생성기 개체가 있으며 항상 다음과 같이 더 큰 피보나치 수를 순서대로 반환합니다.

>>> fibgen1.next(); fibgen1.next(); fibgen1.next(); fibgen1.next()
0
1
1
2
>>> fibgen2.next(); fibgen2.next()
0
1
>>> fibgen1.next(); fibgen1.next()
3
5

생성기의 멋진 점은 객체를 만드는 과정을 거치지 않고 상태를 캡슐화한다는 것입니다. 그것들을 생각하는 한 가지 방법은 그들의 내부 상태를 기억하는 “기능”입니다.

Python Generators 에서 피보나치 예제를 얻었습니다 . 약간의 상상력으로 생성기가 for루프 및 다른 전통적인 반복 구성을 대체 할 수있는 다른 많은 상황을 생각해 낼 수 있습니다 .