programing

"양수" 키워드는 파이썬에서 어떤 역할을 합니까?

elecom 2023. 4. 28. 20:10
반응형

"양수" 키워드는 파이썬에서 어떤 역할을 합니까?

무슨 소용이 있습니까?yield파이썬에서 키워드?그것은 무엇을 합니까?

예를 들어, 이 코드를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  

그리고 이쪽은 전화를 건 사람입니다.

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

메소드가 작동할 때 발생하는 현상_get_child_candidates라고 부릅니까?목록이 반환됩니까??▁is??또 전화하는 거예요?이후 통화는 언제 중단됩니까?


이 코드는 미터법 공간을 위한 훌륭한 파이썬 라이브러리를 만든 Jochen Schulz(jrschulz)에 의해 작성되었습니다.다음은 전체 소스에 대한 링크입니다.모듈 mspace.

무엇을 이해하는 것yield생성기가 무엇인지 이해해야 합니다.발전기를 이해하기 전에 반복 가능한 것들을 이해해야 합니다.

반복 가능한 항목

목록을 만들 때 항목을 하나씩 읽을 수 있습니다.항목을 하나씩 읽는 것을 반복이라고 합니다.

>>> mylist = [1, 2, 3]
>>> for i in mylist:
...    print(i)
1
2
3

mylist참회할 만합니다.목록 이해를 사용하는 경우 목록을 생성하므로 오래 사용할 수 있습니다.

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
...    print(i)
0
1
4

할 수 있는 모든 은 " 용할수있것모든"입니다.for... in...수 있습니다; 에가참할만합다니회;다;lists,strings파일...

이러한 반복 가능한 항목은 원하는 만큼 읽을 수 있기 때문에 유용하지만 모든 값을 메모리에 저장하고 값이 많을 때 항상 원하는 것은 아닙니다.

발전기

생성기는 반복기이며, 한 번만 반복할 수 있습니다.제너레이터는 모든 값을 메모리에 저장하지 않고 즉시 값을 생성합니다.

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...    print(i)
0
1
4

당신이 사용한 것을 제외하고는 동일합니다.()[]그러나 수행할 수 없습니다.for i in mygenerator발전기는 한 번만 사용할 수 있기 때문에 두 번째입니다. 즉, 0을 계산한 다음 잊고 1을 계산한 다음 4를 하나씩 계산합니다.

수익률

yield다음과 같이 사용되는 키워드입니다.return함수가 제너레이터를 반환한다는 점만 제외합니다.

>>> def create_generator():
...    mylist = range(3)
...    for i in mylist:
...        yield i*i
...
>>> mygenerator = create_generator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object create_generator at 0xb7555c34>
>>> for i in mygenerator:
...     print(i)
0
1
4

여기서는 쓸모없는 예이지만 한 번만 읽으면 되는 엄청난 값 집합을 함수가 반환한다는 것을 알고 있으면 유용합니다.

yield함수를 호출할 때 함수 본문에 작성한 코드가 실행되지 않음을 이해해야 합니다.함수는 제너레이터 개체만 반환합니다. 이것은 약간 까다롭습니다.

곳에서부터 계속될 것입니다.for제너레이터를 사용합니다.

이제 어려운 부분:

처음으로for함수에서 생성된 생성기 개체를 호출합니다. 함수에서 코드를 처음부터 시작하여 실행합니다.yield루프의 첫 번째 값을 반환합니다.그런 다음 각 후속 호출은 함수에 작성한 루프의 다른 반복을 실행하고 다음 값을 반환합니다.이는 제너레이터가 비어 있는 것으로 간주될 때까지 계속되며, 이는 기능이 작동하지 않고 실행될 때 발생합니다.yield, 혹은 이 더 일 수도 있습니다, 것은더루만않있고수있때수다습니기당문도지일족하이신상도이그일프문가때끝났기▁that있▁has▁an▁you다니습▁no,▁the수도▁loop▁be▁satisfy▁longer▁because때문않일▁or▁can▁because▁come당▁to고▁an있그."if/else".


코드가 설명되었습니다.

생성기:

# Here you create the method of the node object that will return the generator
def _get_child_candidates(self, distance, min_dist, max_dist):

    # Here is the code that will be called each time you use the generator object:

    # If there is still a child of the node object on its left
    # AND if the distance is ok, return the next child
    if self._leftchild and distance - max_dist < self._median:
        yield self._leftchild

    # If there is still a child of the node object on its right
    # AND if the distance is ok, return the next child
    if self._rightchild and distance + max_dist >= self._median:
        yield self._rightchild

    # If the function arrives here, the generator will be considered empty
    # there are no more than two values: the left and the right children

호출자:

# Create an empty list and a list with the current object reference
result, candidates = list(), [self]

# Loop on candidates (they contain only one element at the beginning)
while candidates:

    # Get the last candidate and remove it from the list
    node = candidates.pop()

    # Get the distance between obj and the candidate
    distance = node._get_dist(obj)

    # If the distance is ok, then you can fill in the result
    if distance <= max_dist and distance >= min_dist:
        result.extend(node._values)

    # Add the children of the candidate to the candidate's list
    # so the loop will keep running until it has looked
    # at all the children of the children of the children, etc. of the candidate
    candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))

return result

이 코드에는 몇 가지 스마트 부품이 포함되어 있습니다.

  • 루프는 목록에서 반복되지만 루프가 반복되는 동안 목록이 확장됩니다.무한 루프가 발생할 수 있기 때문에 다소 위험하더라도 이러한 중첩된 데이터를 모두 살펴볼 수 있는 간단한 방법입니다. 이경에는우,,candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))제너레이터의 모든 값을 소진합니다.while에서는 새 생성기 개체를 계속 생성하며 이 개체는 동일한 노드에 적용되지 않으므로 이전 개체와 다른 값을 생성합니다.

  • extend()method는 반복 가능한 값을 예상하고 해당 값을 목록에 추가하는 목록 개체 메서드입니다.

일반적으로 목록을 전달합니다.

>>> a = [1, 2]
>>> b = [3, 4]
>>> a.extend(b)
>>> print(a)
[1, 2, 3, 4]

하지만 코드에는 발전기가 있는데, 이는 다음과 같은 이유 때문입니다.

  1. 값을 두 번 읽을 필요가 없습니다.
  2. 여러분은 많은 아이들이 있을 수 있고 그들이 모두 메모리에 저장되는 것을 원하지 않을 수 있습니다.

그리고 Python은 메서드의 인수가 목록이든 아니든 상관하지 않기 때문에 작동합니다.Python은 반복 가능하기 때문에 문자열, 목록, 튜플 및 제너레이터와 함께 작동할 것입니다.이것은 오리 타이핑이라고 불리며 파이썬이 멋진 이유 중 하나입니다.하지만 이건 또 다른 이야기야, 다른 질문을 하자면...

여기서 멈추거나 조금 읽어보면 발전기의 고급 사용법을 볼 수 있습니다.

제너레이터 방전 제어

>>> class Bank(): # Let's create a bank, building ATMs
...    crisis = False
...    def create_atm(self):
...        while not self.crisis:
...            yield "$100"
>>> hsbc = Bank() # When everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
$100
>>> print(corner_street_atm.next())
$100
>>> print([corner_street_atm.next() for cash in range(5)])
['$100', '$100', '$100', '$100', '$100']
>>> hsbc.crisis = True # Crisis is coming, no more money!
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.create_atm() # It's even true for new ATMs
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # The trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # Build a new one to get back in business
>>> for cash in brand_new_atm:
...    print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100
...

참고: 파이썬 3의 경우,print(corner_street_atm.__next__())또는print(next(corner_street_atm))

리소스에 대한 액세스 제어와 같은 다양한 작업에 유용할 수 있습니다.

당신의 가장 친한 친구인 Iter tools

리터 도구 모듈에는 반복 가능한 항목을 조작하는 특수 기능이 포함되어 있습니다.발전기를 복제하고 싶은 적이 있습니까?체인 두 발전기?하나의 라이너로 중첩된 목록의 값을 그룹화하시겠습니까? Map / Zip다른 목록을 만들지 않고도?

그냥 ㅠㅠㅠㅠimport itertools.

예를 들면요?네 마리의 경주마가 도착할 수 있는 순서를 알아보겠습니다.

>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
 (1, 2, 4, 3),
 (1, 3, 2, 4),
 (1, 3, 4, 2),
 (1, 4, 2, 3),
 (1, 4, 3, 2),
 (2, 1, 3, 4),
 (2, 1, 4, 3),
 (2, 3, 1, 4),
 (2, 3, 4, 1),
 (2, 4, 1, 3),
 (2, 4, 3, 1),
 (3, 1, 2, 4),
 (3, 1, 4, 2),
 (3, 2, 1, 4),
 (3, 2, 4, 1),
 (3, 4, 1, 2),
 (3, 4, 2, 1),
 (4, 1, 2, 3),
 (4, 1, 3, 2),
 (4, 2, 1, 3),
 (4, 2, 3, 1),
 (4, 3, 1, 2),
 (4, 3, 2, 1)]

반복의 내부 메커니즘 이해

하다는 것을 입니다.__iter__()및method를 하는 것)__next__()방법)을 선택합니다.반복 가능한 개체는 반복기에서 얻을 수 있는 모든 개체입니다.반복기는 반복 가능한 항목을 반복할 수 있는 개체입니다.

기사에는 루프가 어떻게 작동하는지에 대한 자세한 내용이 나와 있습니다.

▁to▁under▁shortcut를 이해하기yield

가 경우는되가 있는 를 볼 때.yield다음과 같은 간단한 방법을 사용하여 앞으로 일어날 일을 이해합니다.

  1. 을 합니다.result = []기능이 시작될 때.
  2. 각항교체를 .yield expr와 함께result.append(expr).
  3. 을 합니다.return result함수의 맨 아래에 있습니다.
  4. 예 - 더 이상 없습니다.yield코드를 읽고 파악합니다.
  5. 함수를 원래 정의와 비교합니다.

이 속임수는 함수 뒤에 있는 논리에 대한 아이디어를 줄 수 있지만 실제로 일어나는 일은yield목록기접방와발서것과는생하에식근(반) 많은 수율 도 훨씬입니다.대부분의 경우, 수율 접근 방식은 훨씬 더 메모리 효율적이고 더 빠릅니다.다른 경우에는, 원래 기능이 잘 작동하더라도 이 속임수는 무한 루프에 갇히게 할 것입니다.자세히 알아보려면 계속 읽어 보십시오.

반복 가능한 항목, 반복기 및 생성기를 혼동하지 마십시오.

첫째, 반복기 프로토콜 - 작성 시

for x in mylist:
    ...loop body...

Python은 다음 두 단계를 수행합니다.

  1. 다음에 대한 반복기를 가져옵니다.mylist:

    iter(mylist) -> 이된 개체를 합니다.next()또는 또방법(는)__next__()Python 3)에서 확인할 수 있습니다.

    [이것은 대부분의 사람들이 여러분에게 말하는 것을 잊는 단계입니다.]

  2. 반복기를 사용하여 다음 항목을 반복합니다.

    계속 전화하기next()1 입니다. 값:next() x루프 본체가 실행됩니다.StopIteration내부에서 상승합니다.next()즉, 반복기에 더 이상 값이 없고 루프가 종료됩니다.

사실 파이썬은 객체의 내용을 루프하고 싶을 때마다 위의 두 단계를 수행합니다. 따라서 for 루프가 될 수 있지만 다음과 같은 코드일 수도 있습니다.otherlist.extend(mylist)서)otherlist는 Python 목록입니다.

여기서mylist반복기 프로토콜을 구현하기 때문에 반복할 수 있습니다.사용자 정의 클래스에서 다음을 구현할 수 있습니다.__iter__()사용자의 인스턴스를 분류할 수 있는 방법입니다. 메서드는 반복기를 반환해야 합니다.반복기는 다음을 가진 객체입니다.next()방법.두 가지를 모두 구현할 수 있습니다.__iter__()그리고.next()같은 반에, 그리고 가지고 있습니다.__iter__()self이 방법은 간단한 경우에 사용할 수 있지만 두 반복기를 동시에 동일한 개체에 루프하려는 경우에는 사용할 수 없습니다.

이것이 반복기 프로토콜입니다. 많은 개체가 이 프로토콜을 구현합니다.

  1. 기본 제공 목록, 사전, 튜플, 세트 및 파일.
  2. 구하사는정클을 구현하는 정의 __iter__().
  3. 발전기.

로 참은 다음과 같습니다.for어떤 - 프로토콜을 이고, 이 프는그다어모떤니 - ▁as▁it▁item▁loop▁item,▁happy▁get▁doesn▁to▁it▁is▁calls▁the▁and▁it기다▁follows니쁩▁with▁-'있서어ator수▁kind's루▁what▁just▁iter▁protocol을▁dealingt▁know▁object▁of얻프하씩나는항을대목것next()기본 제공 목록은 항목을 하나씩 반환하고, 사전은 를 하나씩 반환하며, 파일은 을 하나씩 반환하는 등의 작업을 수행합니다.발전기가 돌아오고,음 거기서yield수신:

def f123():
    yield 1
    yield 2
    yield 3

for item in f123():
    print item

에 에.yield이 세 의 술진, 만개당 3가있이 있었다면.return의술진에 있는 f123()첫 번째만 실행되고 함수는 종료됩니다.그렇지만f123()일반적인 기능이 아닙니다.f123()는 호출되며, 수율 문의 값을 반환하지 않습니다!생성자 개체를 반환합니다.또한 이 기능은 실제로 종료되지 않고 일시 중단 상태가 됩니다.그 때.for객체 에서 루프를 하고, 됩니다. 함수는 다음 줄에서 중단된 상태에서 다시 시작됩니다.yield 이 에는 이에반환코다음줄실을다니이.yield문을 지정하고 다음 항목으로 반환합니다.이는 기능이 종료될 때까지 발생하며, 이때 제너레이터가 상승합니다.StopIteration그리고 루프는 빠져나갑니다.

그래서 제너레이터 객체는 일종의 어댑터와 같습니다. 한쪽 끝에는 노출을 통해 반복기 프로토콜을 표시합니다.__iter__()그리고.next()for 쪽 끝에서는 수 있을 .그러나 다른 쪽에서는 다음 값을 얻을 수 있을 정도로 기능을 실행하고 일시 중단 모드로 되돌립니다.

발전기를 사용하는 이유

일반적으로 제너레이터를 사용하지 않고 동일한 로직을 구현하는 코드를 작성할 수 있습니다.한 가지 방법은 앞서 언급한 임시 리스트 '트릭'을 사용하는 것입니다.예를 들어 무한 루프가 있거나 목록이 너무 긴 경우 메모리를 비효율적으로 사용할 수 있습니다.입니다.next()(또는)__next__()Python 3) 메서드입니다.논에따라, 의코는드 안에 .next()방법은 결국 매우 복잡해 보이고 버그가 발생하기 쉽습니다.여기서 발전기는 깨끗하고 쉬운 솔루션을 제공합니다.

다음과 같이 생각해 보십시오.

반복기는 단지 환상적인 소리를 내는 용어일 뿐입니다.next(). 항복 것이 됩니다.따라서 항복 함수는 결국 다음과 같은 것이 됩니다.

원본 버전:

def some_function():
    for i in xrange(4):
        yield i

for i in some_function():
    print i

이것은 기본적으로 파이썬 인터프리터가 위의 코드로 하는 것입니다.

class it:
    def __init__(self):
        # Start at -1 so that we get 0 when we add 1 below.
        self.count = -1

    # The __iter__ method will be called once by the 'for' loop.
    # The rest of the magic happens on the object returned by this method.
    # In this case it is the object itself.
    def __iter__(self):
        return self

    # The next method will be called repeatedly by the 'for' loop
    # until it raises StopIteration.
    def next(self):
        self.count += 1
        if self.count < 4:
            return self.count
        else:
            # A StopIteration exception is raised
            # to signal that the iterator is done.
            # This is caught implicitly by the 'for' loop.
            raise StopIteration

def some_func():
    return it()

for i in some_func():
    print i

무슨 일이 더 많은 통찰력을 , 서무일대있위통해더을많찰력은한배후에는지슨에이고어일나▁for▁the,위.for루프는 다음으로 다시 작성할 수 있습니다.

iterator = some_func()
try:
    while 1:
        print iterator.next()
except StopIteration:
    pass

그게 더 말이 되나요 아니면 그냥 더 혼란스러운 건가요?:)

나는 이것이 예시적인 목적을 위한 과도한 단순화라는 것에 주목해야 합니다.:)

yield키워드는 두 가지 간단한 사실로 요약됩니다.

  1. 컴파일러가 다음을 감지하는 경우yield키워드는 함수 내부의 어느 곳이든, 그 함수는 더 이상 를 통해 반환되지 않습니다.return진술.대신 생성기라고 하는 게으른 "보류 목록" 개체즉시 반환합니다.
  2. 제너레이터는 반복할 수 있습니다.무엇이 참회할 만한가요?그것은 무엇과도 같습니다.list또는set또는range 요소를 특정 순서로 방문하기 위한 프로토콜이 내장된 ordict-view입니다.

요약하자면, 일반적으로 생성기는 게으르고 증분 보류 중인 목록이며, 명령문을 사용하면 함수 표기법을 사용하여 생성기가 증분으로 뱉어야 하는 목록 값을 프로그래밍할 수 있습니다.또한 고급 사용을 통해 생성기를 코루틴으로 사용할 수 있습니다(아래 참조).

generator = myYieldingFunction(...)  # basically a list (but lazy)
x = list(generator)  # evaluate every element into a list

   generator
       v
[x[0], ..., ???]

         generator
             v
[x[0], x[1], ..., ???]

               generator
                   v
[x[0], x[1], x[2], ..., ???]

                       StopIteration exception
[x[0], x[1], x[2]]     done

▁the,지▁basically▁whenever든,언.yield상태를 따라 "을 내보냅니다"을 으로 호출하는 일부 구문 ).next() 그고를잡다 니습리▁a다▁and를 잡습니다.StopIteration예외 등).생성기 식이 있는 생성기를 사용했을 수 있습니다. 일시 중지된 생성기 함수로 인수를 다시 전달하여 코루틴을 구현할 수 있으므로 생성기 함수가 더 강력합니다.그것에 대한 자세한 내용은 나중에.


기본 예제('list')

해 보겠습니다.makeRange그것은 파이썬의 것과 같습니다.range.부르기makeRange(n) "생성자"를 합니다.

def makeRange(n):
    # return 0,1,2,...,n-1
    i = 0
    while i < n:
        yield i
        i += 1

>>> makeRange(5)
<generator object makeRange at 0x19e4aa0>

값을 이을 생기가보중값인즉을반하로 .list()(당신이 할 수 있는 것처럼):

>>> list(makeRange(5))
[0, 1, 2, 3, 4]

예제를 "그냥 목록 반환"과 비교

위의 예는 단순히 목록을 만들고 목록에 추가하여 반환하는 것으로 간주할 수 있습니다.

# return a list                  #  # return a generator
def makeRange(n):                #  def makeRange(n):
    """return [0,1,2,...,n-1]""" #      """return 0,1,2,...,n-1"""
    TO_RETURN = []               # 
    i = 0                        #      i = 0
    while i < n:                 #      while i < n:
        TO_RETURN += [i]         #          yield i
        i += 1                   #          i += 1
    return TO_RETURN             # 

>>> makeRange(5)
[0, 1, 2, 3, 4]

하지만 한 가지 중요한 차이점이 있습니다. 마지막 섹션을 참조하십시오.


생성기 사용 방법

반복 가능은 목록 이해의 마지막 부분이며 모든 생성기는 반복 가능하기 때문에 다음과 같이 사용됩니다.

#                  < ITERABLE >
>>> [x+10 for x in makeRange(5)]
[10, 11, 12, 13, 14]

발전기를 더 잘 느끼기 위해, 당신은 그것을 가지고 놀 수 있습니다.itertools사용해야 .chain.from_iterablechain필요한 경우).예를 들어 생성기를 사용하여 다음과 같은 무한히 긴 게으른 목록을 구현할 수도 있습니다.itertools.count()은 당신만의 용가직구수있다니습할을 할 수 .def enumerate(iterable): zip(count(), iterable)또는 그 대신에 그것을 수행합니다.yield키워드를 지정합니다.

참고: 발전기는 실제로 코루틴이나 비결정론적 프로그래밍 또는 기타 우아한 것들을 구현하는 것과 같은 더 많은 것들에 사용될 수 있습니다.하지만, 여기서 제가 제시하는 "지루한 목록" 관점은 여러분이 발견할 수 있는 가장 일반적인 용도는 다음과 같습니다.


막후에서

이것이 "파이썬 반복 프로토콜"이 작동하는 방식입니다.즉, 당신이 할 때 무슨 일이 일어나고 있습니까?list(makeRange(5))이것은 제가 앞에서 "지루하고 점진적인 목록"이라고 설명한 것입니다.

>>> x=iter(range(5))
>>> next(x)  # calls x.__next__(); x.next() is deprecated
0
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> next(x)
4
>>> next(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

기능 내장기입니다.next()를 그냥객호출다니합를체▁the다▁calls▁just라고 부릅니다..__next__()함수는 "임의 프로토콜"의 일부이며 모든 반복기에서 찾을 수 있습니다.으로 으로사수다를 할 수 .next()일반적으로 가독성을 희생하면서 화려한 것들을 구현하는 기능(및 반복 프로토콜의 다른 부분), 그러니까 그렇게 하지 않도록 노력하세요...


코루틴스

코루틴 예:

def interactiveProcedure():
    userResponse = yield makeQuestionWebpage()
    print('user response:', userResponse)
    yield 'success'

coroutine = interactiveProcedure()
webFormData = next(coroutine)  # same as .send(None)
userResponse = serveWebForm(webFormData)

# ...at some point later on web form submit...

successStatus = coroutine.send(userResponse)

코루틴(일반적으로 다음을 통해 입력을 수락하는 발전기)yield키워드: 예: nextInput = yield nextOutput양방향 통신의 한 형태로서)는 기본적으로 스스로 일시 중지하고 입력을 요청할 수 있는 계산입니다(예: 다음에 수행해야 할 작업).코루틴이 스스로 일시 중지될 때(실행 중인 코루틴이 결국 다음 값에 도달할 때)yield키워드), 계산이 일시 중지되고 컨트롤이 '슬립' 함수(요청한 프레임)로 다시 반전(되돌려짐).next계산 값)을 입력합니다.일시 중지된 제너레이터/코루틴은 다른 호출 함수(다른 함수/콘텍스트일 수 있음)가 다음 값을 요청하여 일시 중지를 해제할 때까지 일시 중지된 상태로 유지됩니다(일반적으로 일시 중지된 로직 내부를 코루틴의 코드로 안내하는 입력 데이터 전달).

파이썬 코루틴은 게으른 증분 보류 목록으로 생각할 수 있습니다. 여기서 다음 요소는 이전 계산에 의존할 뿐만 아니라 생성 프로세스 중에 주입하기로 선택할 수도 있습니다.


미누티아

보통, 대부분의 사람들은 다음의 구별에 신경 쓰지 않고 아마도 여기서 읽기를 중단하기를 원할 것입니다.

파이썬-speak에서 iterable은 목록과 같이 "for-loop의 개념을 이해하는" 객체입니다.[1,2,3]그리고 반복자는 요청된 for-loop의 특정 인스턴스입니다.[1,2,3].__iter__()생성기는 함수 구문을 사용하여 작성된 방식을 제외하고는 다른 반복기와 정확히 동일합니다.

목록에서 반복기를 요청하면 새 반복기가 생성됩니다.그러나 거의 하지 않는 반복기에서 반복기를 요청하면 해당 반복기 자체의 복사본이 제공됩니다.

그러므로, 만일 당신이 이와 같은 일을 하지 못한다면...

> x = myRange(5)
> list(x)
[0, 1, 2, 3, 4]
> list(x)
[]

그런 다음 제너레이터는 반복기입니다. 즉, 일회용입니다.다시 사용하고 싶다면, 전화를 해야 합니다.myRange(...)다시. 만약 당신이 결과를 두 번 사용해야 한다면, 결과를 목록으로 변환하고 변수에 저장하세요.x = list(myRange(5))복사 가능한 반복기 Python PEP 표준 제안이 연기되었기 때문에 생성기를 복제해야 하는 사람(예: 무섭게 해킹하는 메타프로그래밍을 수행하는 사람)은 필요할 경우 Python 3에서 여전히 작동)을 사용할 수 있습니다.

무엇을 합니까?yield키워드가 파이썬에 있습니까?

답변 개요/요약

  • 함수가 호출되면 제너레이터반환합니다.
  • 생성기는 반복기 프로토콜을 구현하므로 반복기를 반복할 수 있습니다.
  • 생성기는 또한 정보를 전송하여 개념적으로 코루틴으로 만들 수 있습니다.
  • Python 3에서는 을 사용하여 한 제너레이터에서 다른 제너레이터로 양방향으로 위임할 수 있습니다.
  • (부록은 위의 답변을 포함하여 몇 가지 답변을 비판하고 사용법에 대해 설명합니다.return발전기에서.)

생성기:

yield 는 함수 정의 내부에서만 합법적이며 함수 정의에 포함하면 생성기를 반환합니다.

발전기에 대한 아이디어는 다양한 구현을 가진 다른 언어(각주 1 참조)에서 비롯되었습니다.Python's Generators에서 코드 실행은 수율 지점에서 동결됩니다.제너레이터가 호출되면(아래에서 방법에 대해 설명함) 실행이 다시 시작된 다음 다음 수율에서 중지됩니다.

yield에서는 다음 두 가지 방법으로 정의되는 반복기 프로토콜을 쉽게 구현할 수 있는 방법을 제공합니다.__iter__그리고.__next__이 두 가지 방법 모두 객체를 반복자로 만들어 사용자가 입력 검사를 수행할 수 있도록 합니다.Iterator에서 기본 클래스 추상화collections모듈.

def func():
    yield 'I am'
    yield 'a generator!'

몇 가지 자기 성찰을 해 보겠습니다.

>>> type(func)                 # A function with yield is still a function
<type 'function'>
>>> gen = func()
>>> type(gen)                  # but it returns a generator
<type 'generator'>
>>> hasattr(gen, '__iter__')   # that's an iterable
True
>>> hasattr(gen, '__next__')   # and with .__next__
True                           # implements the iterator protocol.

제너레이터 유형은 반복기의 하위 유형입니다.

from types import GeneratorType
from collections.abc import Iterator

>>> issubclass(GeneratorType, Iterator)
True

필요한 경우 다음과 같이 유형을 확인할 수 있습니다.

>>> isinstance(gen, GeneratorType)
True
>>> isinstance(gen, Iterator)
True

의 특징Iterator , 한 소진되면 재사용하거나 재설정할 수 없습니다.

>>> list(gen)
['I am', 'a generator!']
>>> list(gen)
[]

이 기능을 다시 사용하려면 다른 기능을 만들어야 합니다(각주 2 참조).

>>> list(func())
['I am', 'a generator!']

다음과 같은 데이터를 프로그래밍 방식으로 생성할 수 있습니다.

def func(an_iterable):
    for item in an_iterable:
        yield item

위의 단순 생성기도 아래와 같습니다. 파이썬 3.3에서 사용할 수 있습니다.

def func(an_iterable):
    yield from an_iterable

하지만,yield from에서는 하위 생성기에 대한 위임도 허용하며, 하위 코루틴과의 협력 위임에 대한 다음 절에서 설명합니다.

코루틴:

yield는 데이터를 생성기로 전송할 수 있는 식을 형성합니다(각주 3 참조).

여기 예가 있습니다. 다음을 참고하십시오.received변수. 생성기로 전송되는 데이터를 가리킵니다.

def bank_account(deposited, interest_rate):
    while True:
        calculated_interest = interest_rate * deposited 
        received = yield calculated_interest
        if received:
            deposited += received


>>> my_account = bank_account(1000, .05)

먼저, 우리는 내장된 기능으로 발전기를 대기열에 넣어야 합니다. 그것은 적절한 호출을 할 것입니다.next또는__next__사용 중인 Python 버전에 따라 방법:

>>> first_year_interest = next(my_account)
>>> first_year_interest
50.0

이제 데이터를 생성기로 보낼 수 있습니다. (보내는 것은 호출하는 것과 동일합니다.

>>> next_year_interest = my_account.send(first_year_interest + 1000)
>>> next_year_interest
102.5

협력 대표단과 하위-코루틴.yield from

자, 기억하세요.yield fromPython 3에서 사용할 수 있습니다.이를 통해 코루틴을 하위 코루틴에 위임할 수 있습니다.


def money_manager(expected_rate):
    # must receive deposited value from .send():
    under_management = yield                   # yield None to start.
    while True:
        try:
            additional_investment = yield expected_rate * under_management 
            if additional_investment:
                under_management += additional_investment
        except GeneratorExit:
            '''TODO: write function to send unclaimed funds to state'''
            raise
        finally:
            '''TODO: write function to mail tax info to client'''
        

def investment_account(deposited, manager):
    '''very simple model of an investment account that delegates to a manager'''
    # must queue up manager:
    next(manager)      # <- same as manager.send(None)
    # This is where we send the initial deposit to the manager:
    manager.send(deposited)
    try:
        yield from manager
    except GeneratorExit:
        return manager.close()  # delegate?

이제 하위 생성기에 기능을 위임하여 위와 같이 생성기에서 사용할 수 있습니다.

my_manager = money_manager(.06)
my_account = investment_account(1000, my_manager)
first_year_return = next(my_account) # -> 60.0

이제 계정에 1,000개를 더 추가하고 계정 수익률(60.0)을 시뮬레이션해 보십시오.

next_year_return = my_account.send(first_year_return + 1000)
next_year_return # 123.6

의 정확한 의미에 대해 자세히 읽을 수 있습니다.yield fromPEP 380에서.

기타 방법: 닫기 및 던지기

close메소드 상승GeneratorExit함수 실행이 중지된 지점에서.이 또한 다음 사용자가 호출합니다.__del__그래서 당신은 당신이 처리하는 곳에 모든 정리 코드를 넣을 수 있습니다.GeneratorExit:

my_account.close()

생성기에서 처리하거나 사용자에게 다시 전파할 수 있는 예외를 슬로우할 수도 있습니다.

import sys
try:
    raise ValueError
except:
    my_manager.throw(*sys.exc_info())

상승:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "<stdin>", line 6, in money_manager
  File "<stdin>", line 2, in <module>
ValueError

결론

다음 질문의 모든 측면을 다루었다고 생각합니다.

무엇을 합니까?yield키워드가 파이썬에 있습니까?

알고 보니yield많이 합니다.여기에 훨씬 더 철저한 예를 추가할 수 있을 것이라고 확신합니다.당신이 더 원하거나 건설적인 비판이 있다면, 아래의 논평을 통해 저에게 알려주세요.


부록:

최고/인정된 답변에 대한 비판**

  • 예를 들어 목록을 사용하는 것이 무엇을 반복할 수 있게 만드는지 혼란스럽습니다.위의 내 참조를 참조하십시오. 그러나 요약: 반복 가능한 사람은 다음과 같습니다.__iter__반복기를 반환하는 메서드입니다.반복기는 추가적으로 다음을 제공합니다..__next__에 의해 암묵적으로 호출되는 메서드for상승할 때까지 루프StopIteration그리고 그것이 높아지면,StopIteration계속 그렇게 할 것입니다.
  • 그런 다음 생성기 식을 사용하여 생성기가 무엇인지 설명합니다.생성자 표현식은 단순히 반복기를 만드는 편리한 방법이기 때문에, 그것은 단지 문제를 혼란스럽게 할 뿐이고, 우리는 여전히 그것에 도달하지 못했습니다.yield일부.
  • 제너레이터 배기 제어에서 그는 다음과 같이 부릅니다..next메소드(파이썬 2에서만 작동), 대신 그가 내장 함수를 사용해야 할 때,next.부르기next(obj)그의 코드가 파이썬 3에서 작동하지 않기 때문에 적절한 간접 레이어가 될 것입니다.
  • 이터툴스?이것은 무엇과 관련이 없습니다.yield전혀 그렇지 않습니다.
  • 의 방법에 대한 논의는 없습니다.yield새로운 기능과 함께 제공합니다.yield fromPython 3에서.

상위/승인된 답변은 매우 불완전한 답변입니다.

제안하는 답에 대한 비판yield생성자 표현 또는 이해에서.

문법은 현재 목록 이해의 모든 표현을 허용합니다.

expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) |
                     ('=' (yield_expr|testlist_star_expr))*)
...
yield_expr: 'yield' [yield_arg]
yield_arg: 'from' test | testlist

수율은 표현이기 때문에 일부에서는 특별히 우수한 사용 사례를 인용하지 않았음에도 불구하고 이해 또는 생성자 표현에 수율을 사용하는 것이 흥미롭다고 선전했습니다.

CPython 핵심 개발자들은 수당을 폐지하는 것에 대해 논의하고 있습니다.다음은 메일링 목록의 관련 게시물입니다.

2017년 1월 30일 19시 5분에 브렛 캐논은 다음과 같이 썼습니다.

2017년 1월 29일 일요일 16시 39분 크레이그 로드리게스는 다음과 같이 썼습니다.

저는 어느 쪽이든 좋습니다.파이썬 3의 상황을 그대로 두는 것은 좋지 않습니다, IMHO.

제 투표는 구문 오류입니다. 왜냐하면 당신은 구문에서 기대하는 것을 얻지 못했기 때문입니다.

현재의 행동에 의존하는 코드는 너무 영리해서 유지할 수 없기 때문에, 저는 그것이 우리가 끝내기에 합리적인 장소라는 것에 동의합니다.

목표 달성의 측면에서 우리는 다음을 원할 것입니다.

  • 3.7의 구문 경고 또는 사용 중지 경고
  • 2.7.x의 Py3k 경고
  • 3.8의 구문 오류

건배, 닉

닉 코글란 | ncoghlan gmail.com | 호주 브리즈번

게다가, 이것이 결코 좋은 생각이 아닌 방향을 가리키는 것처럼 보이는 미해결 문제(10544)가 있습니다(파이썬으로 작성된 파이썬 구현체인 PyPy는 이미 구문 경고를 제기하고 있습니다).

CPython의 개발자들이 우리에게 다르게 말할 때까지 결론은 다음과 같습니다.생성자 표현이나 이해력을 넣지 마십시오.

return생성기의 문

Python 3의 경우:

생성기 함수에서,return문은 제너레이터가 완료되었으며 이로 인해 발생할 것임을 나타냅니다.StopIteration양육될반환된 값(있는 경우)은 구성 인수로 사용됩니다.StopIteration그리고 그것이 됩니다.StopIteration.value기여하다.

Python 2에서 기록 노트: "제너레이터 함수에서,return문은 다음을 포함할 수 없습니다.expression_list그런 맥락에서, 베어.return제너레이터가 완료되었으며 이로 인해StopIteration"키워야 합니다."expression_list기본적으로 쉼표로 구분된 모든 식입니다. 기본적으로 Python 2에서 생성기를 중지할 수 있습니다.return값을 반환할 수 없습니다.

각주

  1. 생성기 개념을 Python에 도입하기 위한 제안서에는 CLU, Sather 및 Icon 언어가 참조되었습니다.일반적인 생각은 함수가 내부 상태를 유지하고 사용자의 요구에 따라 중간 데이터 지점을 생성할 수 있다는 것입니다.이를 통해 일부 시스템에서는 사용할 수 없는 Python 스레드를 포함한 다른 접근 방식보다 성능이 우수할 것으로 예상됩니다.

  2. 이것은, 예를 들어, 그것을 의미합니다.range사물은 그렇지 않습니다.Iterators, 재사용할 수 있기 때문에 반복할 수 있음에도 불구하고,목록처럼, 그들의__iter__메서드는 반복기 개체를 반환합니다.

  3. yield는 원래 문으로 도입되었으며, 코드 블록에서 줄의 시작 부분에만 나타날 수 있음을 의미합니다.지금이다yield수율 식을 만듭니다.https://docs.python.org/2/reference/simple_stmts.html#grammar-token-yield_stmt 변경은 사용자가 데이터를 수신할 때와 마찬가지로 생성기로 데이터를 전송할 수 있도록 하기 위해 제안되었습니다.데이터를 전송하려면 데이터를 어떤 것에 할당할 수 있어야 하며, 그러기 위해서는 문이 작동하지 않습니다.

yield와 꼭return그것은 당신이 (발전기로서) 알려주는 것을 무엇이든 반환합니다.차이점은 다음 번에 제너레이터를 호출할 때 실행이 마지막 호출부터 시작된다는 것입니다.yield진술.반환과 달리, 스택 프레임은 수율이 발생할 때 정리되지 않지만 제어가 다시 호출자에게 전달되므로 다음에 함수를 호출할 때 상태가 다시 시작됩니다.

코드의 경우, 함수는get_child_candidates목록을 확장할 때 한 번에 하나의 요소를 새 목록에 추가하도록 반복기처럼 작동합니다.

list.extend다 떨어질 때까지 반복자를 호출합니다.당신이 게시한 코드 샘플의 경우 튜플을 반환하고 목록에 추가하는 것이 훨씬 더 명확할 것입니다.

한 가지 더 언급해야 할 것이 있습니다. 산출물을 산출하는 기능은 실제로 종료될 필요가 없습니다.나는 다음과 같은 코드를 작성했습니다.

def fib():
    last, cur = 0, 1
    while True: 
        yield cur
        last, cur = cur, last + cur

그러면 다음과 같은 다른 코드에서 사용할 수 있습니다.

for f in fib():
    if some_condition: break
    coolfuncs(f);

이것은 몇 가지 문제를 단순화하는 데 도움이 되고 몇 가지 문제를 더 쉽게 해결할 수 있습니다.

최소한의 작업 예제를 선호하는 사용자는 이 대화형 Python 세션에 대해 명상해 보십시오.

>>> def f():
...   yield 1
...   yield 2
...   yield 3
... 
>>> g = f()
>>> for i in g:
...   print(i)
... 
1
2
3
>>> for i in g:
...   print(i)
... 
>>> # Note that this time nothing was printed

TL;DR

이 대신:

def square_list(n):
    the_list = []                         # Replace
    for x in range(n):
        y = x * x
        the_list.append(y)                # these
    return the_list                       # lines

수행:

def square_yield(n):
    for x in range(n):
        y = x * x
        yield y                           # with this one.

처음부터 목록을 작성하는 자신을 발견할 때마다yield각각의 조각 대신에 대신.

이것이 저의 첫 수확의 "아하" 순간이었습니다.


yield라고 말하는 것은 달콤한 방법입니다.

일련의 것들을 만듭니다.

동일한 동작:

>>> for square in square_list(4):
...     print(square)
...
0
1
4
9
>>> for square in square_yield(4):
...     print(square)
...
0
1
4
9

다른 동작:

수율은 단일 패스입니다. 한 번만 반복할 수 있습니다.함수에 수율이 있을 때 우리는 그것을 생성 함수라고 부릅니다.그리고 반복기는 그것이 반환하는 것입니다.그 용어들은 공개적입니다.우리는 컨테이너의 편리성을 잃지만, 필요에 따라 임의로 길게 계산된 시리즈의 힘을 얻습니다.

산출량은 게으릅니다. 계산을 뒤로 미루죠.수율이 있는 함수는 호출할 때 실제로 전혀 실행되지 않습니다.중단된 위치를 기억하는 반복기 개체를 반환합니다.전화할 때마다next()반복기(루프에 대해 발생)에서 다음 수율까지 인치 앞으로 실행됩니다. returnStopIteration을 올리고 시리즈를 종료합니다(이것이 for-loop의 자연스러운 끝입니다).

수율은 다용도입니다.데이터를 모두 함께 저장할 필요는 없으며, 한 번에 하나씩 사용할 수 있습니다.무한할 수 있습니다.

>>> def squares_all_of_them():
...     x = 0
...     while True:
...         yield x * x
...         x += 1
...
>>> squares = squares_all_of_them()
>>> for _ in range(4):
...     print(next(squares))
...
0
1
4
9

여러 의 패스가 필요하고 시리즈가 너무 길지 않으면 전화하십시오.list()실행 중:

>>> list(square_yield(4))
[0, 1, 4, 9]

훌륭한 단어 선택yield가지 의미가 모두 적용되기 때문입니다.

수확량 - 생산 또는 제공(예: 농업)

...시리즈의 다음 데이터를 검색합니다.

양보 - 양보 또는 포기(정치 권력에서와 같이)

...반복기가 진행될 때까지 CPU 실행을 포기합니다.

수율은 발전기를 제공합니다.

def get_odd_numbers(i):
    return range(1, i, 2)
def yield_odd_numbers(i):
    for x in range(1, i, 2):
       yield x
foo = get_odd_numbers(10)
bar = yield_odd_numbers(10)
foo
[1, 3, 5, 7, 9]
bar
<generator object yield_odd_numbers at 0x1029c6f50>
bar.next()
1
bar.next()
3
bar.next()
5

보시다시피, 첫 번째 경우에는foo전체 목록을 한 번에 메모리에 저장합니다.5가지 요소가 있는 리스트라면 별 문제가 없지만, 500만개의 리스트를 원한다면 어떨까요?이것은 메모리를 많이 먹을 뿐만 아니라, 기능이 호출되는 시점에 구축하는 데 많은 시간이 소요됩니다.

두 번째 경우에는,bar발전기만 있으면 됩니다.제너레이터는 반복 가능합니다. 즉, 이를 사용할 수 있습니다.for루프 등이 있지만 각 값은 한 번만 액세스할 수 있습니다.모든 값이 동시에 메모리에 저장되는 것은 아닙니다. 생성기 개체는 마지막으로 호출했을 때 루프에 있었던 위치를 "기억"합니다. 이런 식으로 500억까지 셀 수 있는 반복 가능한 숫자를 500억까지 한꺼번에 셀 필요가 없습니다.

다시 말씀드리지만, 이것은 꽤나 고안된 예입니다. 만약 여러분이 정말로 500억까지 세고 싶다면 아마도 그것의 도구를 사용할 것입니다.:)

이것은 발전기의 가장 간단한 사용 사례입니다.말씀하신 것처럼 효율적인 순열을 작성하는 데 사용할 수 있습니다. 어떤 종류의 스택 변수를 사용하는 대신 콜 스택을 통해 물건을 밀어올리는 수율을 사용합니다.생성기는 특수 트리 트래버설 및 기타 모든 방식의 작업에도 사용할 수 있습니다.

발전기를 돌려주고 있습니다.저는 특별히 파이썬에 익숙하지 않지만, 당신이 그것들에 익숙하다면 그것은 C#의 반복기 블록과 같은 종류의 것이라고 생각합니다.

핵심 아이디어는 컴파일러/인터프리터/무엇이든 속임수를 써서 호출자가 next()를 계속 호출하면 생성기 메서드가 일시 중지된 처럼 값을 계속 반환할 수 있다는 입니다.분명히 당신은 메소드를 "일시정지"할 수 없습니다. 그래서 컴파일러는 당신이 현재 어디에 있고 로컬 변수 등이 어떻게 생겼는지 기억할 수 있도록 상태 기계를 만듭니다.이것은 직접 반복기를 쓰는 것보다 훨씬 쉽습니다.

발전기를 사용하는 방법을 설명하는 많은 훌륭한 답변들 중에서 제가 아직 제시되지 않았다고 생각하는 한 가지 유형의 답변이 있습니다.다음은 프로그래밍 언어 이론의 답입니다.

yieldPython의 문은 제너레이터를 반환합니다.Python의 생성기는 연속(특히 코루틴의 한 종류)을 반환하는 함수입니다. 그러나 연속은 무슨 일이 일어나고 있는지 이해하는 더 일반적인 메커니즘을 나타냅니다.

프로그래밍 언어 이론에서의 연속성은 훨씬 더 기본적인 종류의 계산이지만 자주 사용되지는 않습니다. 왜냐하면 그것들은 추론하기가 극도로 어렵고 실행하기도 매우 어렵기 때문입니다.그러나 연속이 무엇인지에 대한 아이디어는 간단합니다. 아직 끝나지 않은 계산 상태입니다.이 상태에서는 변수의 현재 값, 아직 수행되지 않은 작업 등이 저장됩니다.그런 다음 프로그램의 나중에 프로그램 변수가 해당 상태로 재설정되고 저장된 작업이 수행되도록 계속을 호출할 수 있습니다.

연속성은 보다 일반적인 형태로 두 가지 방법으로 구현될 수 있습니다.에서call/ccway, 프로그램의 스택은 문자 그대로 저장된 다음 계속이 호출되면 스택이 복원됩니다.

연속 전달 스타일(CPS)에서 연속은 프로그래머가 명시적으로 관리하고 서브루틴으로 전달하는 일반 함수일 뿐입니다.이 스타일에서 프로그램 상태는 스택의 어딘가에 있는 변수가 아니라 폐쇄(및 그 안에 인코딩되는 변수)로 표시됩니다.제어 흐름을 관리하는 함수는 연속성을 인수로 수락하고(일부 CPS 버전에서는 함수가 여러 개의 연속성을 허용할 수 있음) 단순히 호출하고 나중에 반환하여 제어 흐름을 조작합니다.연속 전달 스타일의 매우 간단한 예는 다음과 같습니다.

def save_file(filename):
  def write_file_continuation():
    write_stuff_to_file(filename)

  check_if_file_exists_and_user_wants_to_overwrite(write_file_continuation)

이 (매우 단순한) 예에서 프로그래머는 파일을 실제로 쓰는 작업을 연속체에 저장한 다음(잠재적으로 많은 세부사항을 적어야 하는 매우 복잡한 작업일 수 있음) 그 연속체를 더 많은 처리를 하는 다른 운영자에게 전달합니다.필요한 경우 호출합니다. (이 디자인 패턴을 실제 GUI 프로그래밍에서 많이 사용하는 이유는 코드 줄을 저장하거나 GUI 이벤트 트리거 후 제어 흐름을 관리하기 때문입니다.)

이 게시물의 나머지 부분은 일반성을 잃지 않고 연속성을 CPS로 개념화할 것입니다. 이해하고 읽기가 훨씬 쉽기 때문입니다.


이제 Python의 발전기에 대해 이야기해 보겠습니다.제너레이터는 연속성의 특정 하위 유형입니다.연속은 일반적으로 계산 상태(즉, 프로그램의 호출 스택)를 저장할 수 있는 반면, 생성자반복기 통해 반복 상태만 저장할 수 있습니다.그러나 이 정의는 제너레이터의 특정 사용 사례에 대해 약간 오해를 불러일으킵니다.예를 들어:

def f():
  while True:
    yield 4

이것은 동작이 잘 정의된 합리적인 반복성입니다. 생성기가 반복할 때마다 4를 반환합니다(그리고 영원히 그렇게 합니다).그러나 반복기(즉, 반복기)를 생각할 때 생각나는 전형적인 유형의 반복기는 아닐 것입니다.for x in collection: do_something(x)이 예는 발전기의 힘을 보여줍니다. 만약 어떤 것이 반복기라면, 발전기는 그 반복의 상태를 저장할 수 있습니다.

반복하기:연속은 프로그램 스택의 상태를 저장하고 생성자는 반복 상태를 저장할 수 있습니다.이것은 연속성이 발전기보다 훨씬 더 강력하다는 것을 의미하지만 발전기가 훨씬 더 쉽다는 것을 의미합니다.언어 설계자가 구현하기 쉽고 프로그래머가 사용하기도 쉽습니다(구울 시간이 있는 경우 계속 호출/cc에 대한페이지를 읽고 이해해 보십시오).

그러나 생성기를 단순하고 구체적인 연속 전달 방식으로 구현(그리고 개념화)할 수 있습니다.

언제든지yield이 호출되면 함수에 연속을 반환하도록 지시합니다.함수가 다시 호출되면, 함수는 중단된 위치에서 시작됩니다.따라서 유사 유사 코드(즉, 유사 코드는 아니지만 코드는 아님)에서 생성자의next방법은 기본적으로 다음과 같습니다.

class Generator():
  def __init__(self,iterable,generatorfun):
    self.next_continuation = lambda:generatorfun(iterable)

  def next(self):
    value, next_continuation = self.next_continuation()
    self.next_continuation = next_continuation
    return value

어디서yield키워드는 실제로 실제 생성기 함수에 대한 통사적 설탕이며, 기본적으로 다음과 같습니다.

def generatorfun(iterable):
  if len(iterable) == 0:
    raise StopIteration
  else:
    return (iterable[0], lambda:generatorfun(iterable[1:]))

이것은 단지 의사 코드일 뿐이고 Python에서 생성기의 실제 구현은 더 복잡하다는 것을 기억하십시오.그러나 무슨 일이 일어나고 있는지 이해하기 위한 연습으로 연속 전달 스타일을 사용하여 다음을 사용하지 않고 생성기 객체를 구현하려고 합니다.yield키워드

여기 쉬운 언어로 된 예가 있습니다.저는 높은 수준의 인간 개념과 낮은 수준의 파이썬 개념 간의 대응을 제공할 것입니다.

저는 일련의 숫자에 대해 수술을 하고 싶지만, 저는 그 수열을 만드는 것에 대해 저 자신을 괴롭히고 싶지 않습니다. 저는 단지 제가 하고 싶은 수술에만 집중하고 싶습니다.그래서 저는 다음을 수행합니다.

  • 저는 당신에게 전화를 해서 특정한 방법으로 계산된 일련의 숫자를 원한다고 말하고, 알고리즘이 무엇인지 알려줍니다.
    이 단계는 다음에 해당합니다.def생성기 함수에서, 즉, 다음을 포함하는 함수에서.yield.
  • 나중에, 저는 여러분에게 "좋아요, 숫자의 순서를 알려줄 준비를 하세요."라고 말합니다.
    이 단계는 제너레이터 개체를 반환하는 제너레이터 함수를 호출하는 것에 해당합니다.참고로 당신은 아직 숫자를 알려주지 않고 종이와 연필만 잡습니다.
  • 제가 "다음 번호를 알려주세요"라고 물으면, 첫 번째 번호를 알려주시면, 그 다음 번호를 제가 물어볼 때까지 기다리시게 됩니다.당신이 어디에 있었는지, 당신이 이미 말한 숫자는 무엇인지, 그리고 다음 숫자는 무엇인지 기억하는 것이 여러분의 일입니다.세부 사항은 신경 안 써요.
    이 단계는 호출에 해당합니다.next(generator)생성기 개체에 있습니다.
    (Python 2의 경우).next생성기 개체의 메서드입니다. 파이썬 3에서는 이름이 지정됩니다..__next__하지만 적절한 호칭은 내장된 기능을 사용하는 것입니다.next()와 같은 기능을 합니다.len()그리고..__len__)
  • 이전 단계를 반복합니다.
  • 결국, 당신은 끝날지도 모릅니다.번호를 알려주지도 않고, "말을 멈추세요!"라고 외칩니다.끝났어요!숫자는 이제 그만!"
    이 단계는 생성기 개체가 작업을 종료하고 다음을 발생시키는 것에 해당합니다.StopIteration예외.
    제너레이터 기능은 예외를 발생시킬 필요가 없습니다.함수가 종료되거나 다음을 실행할 때 자동으로 상승됩니다.return.

이는 제너레이터가 수행하는 작업입니다(다음을 포함하는 함수).yield); 첫 번째에 실행을 시작합니다.next()를 실행할 때마다 일시 중지됩니다.yield그리고 요청을 받았을 때next()값은 마지막 지점부터 계속됩니다.순차적으로 값을 요청하는 방법을 설명하는 Python의 반복기 프로토콜과 설계상 완벽하게 일치합니다.

반복기 프로토콜의 가장 유명한 사용자는for명령을 사용할 수 있습니다.그래서, 당신이 할 때마다:

for item in sequence:

해도 상관없습니다sequence는 위에서 설명한 것과 같은 목록, 문자열, 사전 또는 생성기 개체입니다. 결과는 동일합니다. 즉, 시퀀스에서 항목을 하나씩 읽습니다.

참고:def를 포함하는 함수에서yield키워드는 생성기를 만드는 유일한 방법이 아니라 생성기를 만드는 가장 쉬운 방법입니다.

자세한 내용은 Python 설명서의 반복기 유형, 산출물 설명생성기를 참조하십시오.

많은 답변이 사용 이유를 보여주지만,yield생성기를 생성하기 위해 더 많은 용도가 있습니다.yield코루틴을 만드는 것은 매우 쉬우며, 이것은 두 개의 코드 블록 사이에 정보를 전달할 수 있게 합니다.이미 제공된 사용에 대한 좋은 예를 반복하지 않겠습니다.yield생성기를 생성합니다.

무엇을 이해하는 데 도움이 되는 것.yield다음 코드에서, 당신은 당신의 손가락을 사용하여 사이클을 추적할 수 있습니다.yield손가락이 닿을 때마다yield당신은 기다려야 합니다.next또는send입력할 것.의 경우next라고 불리는, 당신은 당신이 그것을 칠 때까지 코드를 추적합니다.yield오른쪽에 있는 암호yield평가되어 호출자에게 반환됩니다. 그런 다음 기다리십시오.언제next다시 호출되면 코드를 통해 다른 루프를 수행합니다.하지만, 코루틴을 보면,yield다음과 함께 사용할 수도 있습니다.send호출자로부터 항복 함수로 값을 전송합니다.만약에send주어진 경우yield전송된 값을 수신하고 왼쪽으로 뱉습니다. 그러면 코드를 통해 추적이 진행됩니다.yield다시 (마지막에 값을 계산하는 것처럼)next호출됨).

예:

>>> def coroutine():
...     i = -1
...     while True:
...         i += 1
...         val = (yield i)
...         print("Received %s" % val)
...
>>> sequence = coroutine()
>>> sequence.next()
0
>>> sequence.next()
Received None
1
>>> sequence.send('hello')
Received hello
2
>>> sequence.close()

또 있습니다.yield사용 및 의미(Python 3.3 이후):

yield from <expr>

PEP 380 - 하위 생성기에 위임하기 위한 구문:

생성기에 대해 작업의 일부를 다른 생성기에 위임하는 구문이 제안됩니다.이를 통해 '수익률'을 포함하는 코드 섹션을 인수 분해하여 다른 생성기에 배치할 수 있습니다.또한 하위 생성기는 값을 반환할 수 있으며, 값은 위임 생성기에서 사용할 수 있습니다.

또한 새로운 구문은 한 발전기가 다른 발전기에서 생성된 값을 다시 산출할 때 최적화할 수 있는 몇 가지 기회를 제공합니다.

게다가 이것은 (파이썬 3.5 이후) 다음을 도입할 것입니다.

async def new_coroutine(data):
   ...
   await blocking_action()

코루틴이 일반 발전기와 혼동되는 것을 피하기 위해 (오늘날)yield둘 다 사용됨).

모두 훌륭한 답변들이지만, 초보자들에게는 조금 어렵습니다.

나는 당신이 그것을 배웠다고 생각합니다.return진술.

비유하자면,return그리고.yield쌍둥이입니다. return'반환 및 중지'를 의미하는 반면 '수익률'은 '반환, 그러나 계속'을 의미합니다.

  1. 다음을 사용하여 num_list를 가져옵니다.return.
def num_list(n):
    for i in range(n):
        return i

실행:

In [5]: num_list(3)
Out[5]: 0

보세요, 당신은 그것들의 목록이 아닌 하나의 숫자만 받습니다. return행복하게 승리하는 것을 절대 허용하지 않습니다. 단 한 번만 구현하고 그만두십시오.

  1. 자!yield

교체하다return와 함께yield:

In [10]: def num_list(n):
    ...:     for i in range(n):
    ...:         yield i
    ...:

In [11]: num_list(3)
Out[11]: <generator object num_list at 0x10327c990>

In [12]: list(num_list(3))
Out[12]: [0, 1, 2]

자, 여러분이 이겨서 모든 숫자를 얻습니다.

와 비교하여return한 번 달리고 멈추면,yield계획한 시간을 실행합니다.해석할 수 있습니다.return~하듯이return one of them,그리고.yield~하듯이return all of them이를 다음이라고 합니다.iterable.

  1. 한 단계 더 우리가 다시 쓸 수 있습니다.yield와의 진술.return
In [15]: def num_list(n):
    ...:     result = []
    ...:     for i in range(n):
    ...:         result.append(i)
    ...:     return result

In [16]: num_list(3)
Out[16]: [0, 1, 2]

에 대한 핵심입니다.yield.

목록 간의 차이return출력 및 객체yield출력:

항상 목록 개체에서 [0, 1, 2]을(를) 가져오지만 '개체'에서만 검색할 수 있습니다.yield출력' 1회그래서, 그것은 새로운 이름을 가지고 있습니다.generator에 표시된 개체Out[11]: <generator object num_list at 0x10327c990>.

결론적으로, 그것을 더듬기 위한 은유로서:

  • return그리고.yield쌍둥이입니다
  • list그리고.generator쌍둥이입니다

프로그래밍의 관점에서, 반복기는 thunk로 구현됩니다.

뒤에yield구문에는 의미론이 있어야 합니다.구문 뒤에 있는 의미론적 개념을 이해하는 것이 중요합니다.예를 들어, 마감을 작성하려면 다음과 같이 하십시오.lambda그리고.def발전기는 단순한 폐쇄입니까?제너레이터가 스택을 저장합니까?확실히 스택은 저장되지 않습니다.call-with-current-continuation그래요, 파이썬 실행 모델이 트리가 아니기 때문에...그리고 발전기는 단순한 폐쇄가 아닙니다. 그렇지 않으면 함수와 발전기는 같은 개념이 될 것입니다.그래서 저는 발전기의 개념을 좀 더 기본적인 폐쇄 개념으로 만들어서 이해하려고 합니다.

동시 실행을 위한 반복자, 생성기 및 스레드 풀 등을 thunk로 구현하기 위해 디스패처가 있는 폐쇄 개체로 전송된 메시지를 사용하고 디스패처가 "메시지"에 응답합니다.

"다음"은 "iter" 호출에 의해 만들어진 종료로 전송되는 메시지입니다.

이 계산을 구현하는 방법은 여러 가지가 있습니다.저는 돌연변이를 사용했지만, 현재 값과 다음 항복자(참조 투명하게 함)를 반환함으로써 돌연변이 없이 이런 종류의 계산이 가능합니다.라켓은 일부 중간 언어에서 초기 프로그램의 일련의 변환을 사용하며, 이러한 재작성 중 하나는 수율 연산자를 더 간단한 연산자로 일부 언어로 변환하도록 만듭니다.

다음은 R6RS의 구조를 사용하는 수율을 다시 작성하는 방법에 대한 시연이지만 의미론은 Python의 구조와 동일합니다.동일한 계산 모델이며 Python의 수율을 사용하여 다시 작성하려면 구문만 변경하면 됩니다.

Welcome to Racket v6.5.0.3.

-> (define gen
     (lambda (l)
       (define yield
         (lambda ()
           (if (null? l)
               'END
               (let ((v (car l)))
                 (set! l (cdr l))
                 v))))
       (lambda(m)
         (case m
           ('yield (yield))
           ('init  (lambda (data)
                     (set! l data)
                     'OK))))))
-> (define stream (gen '(1 2 3)))
-> (stream 'yield)
1
-> (stream 'yield)
2
-> (stream 'yield)
3
-> (stream 'yield)
'END
-> ((stream 'init) '(a b))
'OK
-> (stream 'yield)
'a
-> (stream 'yield)
'b
-> (stream 'yield)
'END
-> (stream 'yield)
'END
->

다음은 Python이 구문 설탕을 제공하지 않은 것처럼 제너레이터를 실제로 구현하는 방법에 대한 몇 가지 Python 예입니다.

Python 생성기로서:

from itertools import islice

def fib_gen():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a + b

assert [1, 1, 2, 3, 5] == list(islice(fib_gen(), 5))

생성기 대신 어휘 폐쇄 사용

def ftake(fnext, last):
    return [fnext() for _ in xrange(last)]

def fib_gen2():
    #funky scope due to python2.x workaround
    #for python 3.x use nonlocal
    def _():
        _.a, _.b = _.b, _.a + _.b
        return _.a
    _.a, _.b = 0, 1
    return _

assert [1,1,2,3,5] == ftake(fib_gen2(), 5)

생성기 대신 객체 폐쇄 사용(폐쇄 및 객체가 동일하므로)

class fib_gen3:
    def __init__(self):
        self.a, self.b = 1, 1

    def __call__(self):
        r = self.a
        self.a, self.b = self.b, self.a + self.b
        return r

assert [1,1,2,3,5] == ftake(fib_gen3(), 5)

"발전기에 대한 빠른 설명을 위해 비즐리의 '파이썬: 에센셜 레퍼런스' 19페이지를 읽으려고 했는데, 다른 많은 사람들이 이미 좋은 설명을 게시했습니다.

또한, 참고로yield코루틴에서 제너레이터 기능의 이중으로 사용할 수 있습니다.비록 당신의 코드 스니펫과 같은 용도는 아니지만,(yield)함수의 표현식으로 사용할 수 있습니다.호출자가 다음을 사용하여 메서드에 값을 보낼 때send()방법, 그리고 나서 코루틴은 다음까지 실행될 것입니다.(yield)문이 발견되었습니다.

생성기와 코루틴은 데이터 흐름 유형 응용 프로그램을 설정하는 좋은 방법입니다.저는 그것의 다른 용도에 대해 알 가치가 있다고 생각했습니다.yield함수의 문입니다.

다음은 간단한 예입니다.

def isPrimeNumber(n):
    print "isPrimeNumber({}) call".format(n)
    if n==1:
        return False
    for x in range(2,n):
        if n % x == 0:
            return False
    return True

def primes (n=1):
    while(True):
        print "loop step ---------------- {}".format(n)
        if isPrimeNumber(n): yield n
        n += 1

for n in primes():
    if n> 10:break
    print "writing result {}".format(n)

출력:

loop step ---------------- 1
isPrimeNumber(1) call
loop step ---------------- 2
isPrimeNumber(2) call
loop step ---------------- 3
isPrimeNumber(3) call
writing result 3
loop step ---------------- 4
isPrimeNumber(4) call
loop step ---------------- 5
isPrimeNumber(5) call
writing result 5
loop step ---------------- 6
isPrimeNumber(6) call
loop step ---------------- 7
isPrimeNumber(7) call
writing result 7
loop step ---------------- 8
isPrimeNumber(8) call
loop step ---------------- 9
isPrimeNumber(9) call
loop step ---------------- 10
isPrimeNumber(10) call
loop step ---------------- 11
isPrimeNumber(11) call

저는 파이썬 개발자는 아니지만, 제가 보기에는 그렇습니다.yield프로그램 흐름의 위치와 다음 루프 시작 위치를 "양력" 위치에서 유지합니다.그 위치에서 기다리고 있는 것 같고, 그 직전에 밖으로 값을 돌려주고, 다음에도 계속 작동하는 것 같습니다.

그것은 흥미롭고 멋진 능력인 것 같습니다.d

이것은 무엇에 대한 정신적 이미지입니다.yield한다.

저는 스레드가 스택을 가지고 있다고 생각합니다(그렇게 구현되지 않은 경우에도).

일반 함수가 호출되면 로컬 변수를 스택에 배치하고 계산을 수행한 다음 스택을 지우고 반환합니다.로컬 변수의 값은 다시는 표시되지 않습니다.

와 함께yield함수, 코드가 실행되기 시작할 때(즉, 함수가 호출된 후, 다음의 생성자 개체를 반환합니다.next()그런 다음 메소드가 호출됩니다). 마찬가지로 로컬 변수를 스택에 배치하고 잠시 동안 계산합니다.하지만 그 때, 그것이 부딪쳤을 때.yieldstatement는 스택의 일부를 지우고 돌아가기 전에 로컬 변수의 스냅샷을 만들어 생성기 개체에 저장합니다.또한 코드에 현재 위치(즉, 특정 위치)를 기록합니다.yield진술).

이것은 일종의 냉동 기능으로 발전기가 매달리고 있습니다.

언제next()는 이후에 호출되며 함수의 소유물을 스택으로 검색하고 다시 애니메이션화합니다.이 기능은 콜드 스토리지에서 영원한 시간을 보냈다는 사실을 망각한 채 중단된 부분부터 계속 계산합니다.

다음 예를 비교합니다.

def normalFunction():
    return
    if False:
        pass

def yielderFunction():
    return
    if False:
        yield 12

두 번째 함수를 호출하면 첫 번째 함수와 매우 다르게 동작합니다.yield진술은 도달할 수 없을지도 모르지만, 만약 그것이 어디에든 있다면, 그것은 우리가 다루고 있는 것의 본질을 바꿉니다.

>>> yielderFunction()
<generator object yielderFunction at 0x07742D28>

부르기yielderFunction()코드를 실행하지 않고 코드로 제너레이터를 만듭니다.(아마도 그런 것들에 이름을 붙이는 것은 좋은 생각일 것입니다.yielder가독성을 위한 접두사.)

>>> gen = yielderFunction()
>>> dir(gen)
['__class__',
 ...
 '__iter__',    #Returns gen itself, to make it work uniformly with containers
 ...            #when given to a for loop. (Containers return an iterator instead.)
 'close',
 'gi_code',
 'gi_frame',
 'gi_running',
 'next',        #The method that runs the function's body.
 'send',
 'throw']

gi_code그리고.gi_frame필드는 동결 상태가 저장되는 곳입니다.를 사용한 탐색dir(..)우리는 위의 우리의 정신적 모델이 신뢰할 수 있다는 것을 확인할 수 있습니다.

여러분이 하루에 수천 개의 전구를 생성할 수 있는 놀라운 기계를 만들었다고 상상해 보세요.기기는 고유한 일련 번호를 가진 상자에 이러한 전구를 생성합니다.이 모든 전구를 동시에 저장할 공간이 부족하기 때문에 필요에 따라 전구를 생성하도록 전구를 조정하려고 합니다.

파이썬 생성기는 이 개념과 크게 다르지 않습니다.당신에게 다음과 같은 기능이 있다고 상상해보세요.barcode_generator상자에 대한 고유 일련 번호를 생성합니다.기능에서 반환되는 바코드가 하드웨어(RAM) 제한에 따라 매우 많을 수 있습니다.보다 현명하고 공간 효율적인 옵션은 이러한 일련 번호를 필요에 따라 생성하는 것입니다.

컴퓨터 코드:

def barcode_generator():
    serial_number = 10000  # Initial barcode
    while True:
        yield serial_number
        serial_number += 1


barcode = barcode_generator()
while True:
    number_of_lightbulbs_to_generate = int(input("How many lightbulbs to generate? "))
    barcodes = [next(barcode) for _ in range(number_of_lightbulbs_to_generate)]
    print(barcodes)

    # function_to_create_the_next_batch_of_lightbulbs(barcodes)

    produce_more = input("Produce more? [Y/n]: ")
    if produce_more == "n":
        break

참고:next(barcode)조금.

보시다시피, 매번 고유한 일련 번호를 생성하는 자체 "기능"이 있습니다.이 함수는 제너레이터를 반환합니다!보시다시피, 우리는 새로운 일련 번호가 필요할 때마다 함수를 호출하지 않고 대신 사용하고 있습니다.next()다음 일련 번호를 얻기 위해 제너레이터가 지정됩니다.

게으른 반복자들

더 정확히 말하면, 이 발전기는 게으른 반복기입니다!반복기는 우리가 일련의 물체를 통과하도록 도와주는 물체입니다.필요할 때까지 시퀀스의 모든 항목을 메모리에 로드하지 않기 때문에 레이지라고 합니다.의 사용next앞의 예에서는 반복기에서 다음 항목을 얻는 명시적인 방법입니다.암시적 방법은 루프에 사용됩니다.

for barcode in barcode_generator():
    print(barcode)

이렇게 하면 바코드가 무한정 인쇄되지만 메모리가 부족하지는 않습니다.

즉, 생성기는 함수처럼 보이지만 반복기처럼 작동합니다.

실제 애플리케이션?

마지막으로, 실제 애플리케이션?일반적으로 큰 시퀀스로 작업할 때 유용합니다.수십억 개의 레코드가 있는 디스크에서 거대한 파일을 읽는다고 상상해 보십시오.내용을 작업하기 전에 메모리에 있는 전체 파일을 읽는 것은 불가능할 수 있습니다(즉, 메모리가 부족하게 됩니다.

이해하기 쉬운 예:yield

def f123():
    for _ in range(4):
        yield 1
        yield 2


for i in f123():
    print (i)

출력은 다음과 같습니다.

1 2 1 2 1 2 1 2

모든 대답이 암시하듯이,yield는 시퀀스 생성기를 생성하는 데 사용됩니다.동적으로 어떤 시퀀스를 생성하는 데 사용됩니다.예를 들어 네트워크에서 파일을 한 줄씩 읽는 동안yield기능은 다음과 같습니다.

def getNextLines():
   while con.isOpen():
       yield con.read()

코드에서 다음과 같이 사용할 수 있습니다.

for line in getNextLines():
    doSomeThing(line)

실행 제어 전송 gotcha

실행 제어가 getNextLines()에서 다음으로 전송됩니다.for항복이 실행될 때 루프.따라서 getNextLines()가 호출될 때마다 마지막으로 일시 중지된 지점부터 실행이 시작됩니다.

즉, 다음과 같은 코드를 갖는 함수

def simpleYield():
    yield "first time"
    yield "second time"
    yield "third time"
    yield "Now some useful value {}".format(12)

for i in simpleYield():
    print i

인쇄 예정

"first time"
"second time"
"third time"
"Now some useful value 12"

(아래 답변은 Python generator를 사용하는 관점에서만 말하는 것이지 스택 및 힙 조작의 몇 가지 트릭을 포함하는 제너레이터 메커니즘의 기본 구현은 아닙니다.)

언제yield대신 사용됩니다.return파이썬 함수에서, 그 함수는 라고 불리는 특별한 것으로 바뀝니다.generator function이 함수는 다음 개체를 반환합니다.generatortype. 키워드는 python 컴파일러에 이러한 기능을 특별히 처리하도록 알리는 플래그입니다.일부 값이 반환되면 정상 기능이 종료됩니다.그러나 컴파일러의 도움으로 제너레이터 기능은 재개 가능하다고 생각할 수 있습니다.즉, 실행 컨텍스트가 복원되고 마지막 실행부터 실행이 계속됩니다.당신이 명시적으로 리턴을 부를 때까지, 그것은 다음을 제기할 것입니다.StopIteration예외(반복 프로토콜의 일부이기도 함) 또는 함수의 끝에 도달합니다.에 대한 많은 참고 자료를 찾았습니다.generator하지만 이것은 그의 것입니다.functional programming perspective가 가장 소화가 잘 됩니다.

(이제 저는 뒤에 있는 이론적 근거에 대해 이야기하고 싶습니다.generator그리고iterator제가 이해한 바로는.이것이 반복기와 발전기의 본질적인 동기를 파악하는 데 도움이 되기를 바랍니다.이러한 개념은 C#과 같은 다른 언어에서도 나타납니다.)

제가 알기로는, 우리가 많은 데이터를 처리하고자 할 때, 우리는 보통 데이터를 어딘가에 먼저 저장한 다음 하나씩 처리합니다.하지만 이 순진한 접근법은 문제가 있습니다.데이터 볼륨이 크면 사전에 데이터를 전체적으로 저장하는 데 비용이 많이 듭니다.따라서자체를 직접 저장하는 대신 간접적으로 저장하는 것이 어떨까요?

이러한 메타데이터를 래핑하는 방법에는 두 가지가 있습니다.

  1. OOO 접근 방식은 메타데이터를 포장합니다.as a class이것은 소위 말하는 것입니다.iterator누가 반복자 프로토콜을 구현하는지(즉,__next__(),그리고.__iter__()방법)을 선택합니다.이것은 또한 흔히 볼 수 있는 반복기 설계 패턴입니다.
  2. 기능적 접근법은 메타데이터를 랩으로 감습니다.as a function이것은 소위 말하는 것입니다.generator function하지만 후드 아래에서 돌아온 사람들은generator object여전히IS-A반복기 프로토콜도 구현하기 때문에 반복기.

어느 쪽이든 반복기가 생성됩니다. 즉, 원하는 데이터를 제공할 수 있는 개체가 생성됩니다.OOO의 접근 방식은 다소 복잡할 수 있습니다.어쨌든, 어떤 것을 사용할지는 당신에게 달려 있습니다.

요약하자면,yield문은 당신의 기능을 공장으로 변환합니다. 그것은 a라고 불리는 특별한 물체를 생산합니다.generator당신의 원래 기능의 몸을 감싸고 있습니다.그 때.generator반복됩니다. 다음에 도달할 때까지 기능을 실행합니다.yield그런 다음 실행을 일시 중단하고 전달된 값으로 평가합니다.yield실행 경로가 함수를 종료할 때까지 각 반복에서 이 프로세스를 반복합니다.예를 들어.

def simple_generator():
    yield 'one'
    yield 'two'
    yield 'three'

for i in simple_generator():
    print i

단순 산출물

one
two
three

전력은 시퀀스를 계산하는 루프가 있는 제너레이터를 사용하여 발생합니다. 제너레이터는 매번 루프 중지를 실행하여 계산의 다음 결과를 '생산'합니다. 이러한 방식으로 목록을 즉시 계산합니다. 특히 큰 계산을 위해 절약되는 메모리의 이점이 있습니다.

자신의 것을 만들고 싶다고 말합니다.range반복 가능한 범위의 숫자를 생성하는 함수, 당신은 그렇게 할 수 있습니다.

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

이렇게 사용합니다.

for i in myRangeNaive(10):
    print i

하지만 이것은 비효율적입니다 왜냐하면

  • 한 번만 사용하는 어레이를 생성하면 메모리가 낭비됩니다.
  • 이 코드는 실제로 해당 어레이를 두 번 루프합니다! :(

다행히 Guido와 그의 팀은 발전기를 개발할 만큼 충분히 관대해서 우리는 이것을 할 수 있었습니다.

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

for i in myRangeSmart(10):
    print i

이제 각 반복에서 발생기의 함수는 다음과 같습니다.next()함수가 정지하고 값을 '슬립'하거나 함수의 끝에 도달할 때까지 함수를 실행합니다.이 경우 첫 번째 통화에서next()수율 문까지 실행하고 'n'을 산출하면, 다음 호출에서 증분 문을 실행하고 'while'로 다시 점프하여 평가하며, true인 경우 중지하고 다시 'n'을 산출합니다. 반면 조건이 거짓으로 반환되고 생성기가 함수의 끝으로 점프할 때까지 이러한 방식으로 계속됩니다.

수율은 객체입니다.

A return함수에서 단일 값을 반환합니다.

함수가 큰 값 집합을 반환하도록 하려면 다음을 사용합니다.yield.

더 중요한 것은yield장벽입니다.

CUDA 언어의 장벽처럼, 그것은 완성될 때까지 통제권을 이전하지 않을 것입니다.

즉, 처음부터 시작하여 실행될 때까지 함수의 코드를 실행합니다.yield그러면 루프의 첫 번째 값이 반환됩니다.

그러면 다른 모든 호출이 함수에 기록한 루프를 한 번 더 실행하여 반환할 값이 없을 때까지 다음 값을 반환합니다.

많은 사람들이 사용합니다.return보다는yield하지만 어떤 경우에는yield보다 효율적이고 쉽게 작업할 수 있습니다.

다음은 다음과 같은 예가 있습니다.yield다음과 같은 경우에 가장 적합합니다.

반환(기능 중)

import random

def return_dates():
    dates = [] # With 'return' you need to create a list then return it
    for i in range(5):
        date = random.choice(["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th"])
        dates.append(date)
    return dates

산출량(기능중)

def yield_dates():
    for i in range(5):
        date = random.choice(["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th"])
        yield date # 'yield' makes a generator automatically which works
                   # in a similar way. This is much more efficient.

호출 기능

dates_list = return_dates()
print(dates_list)
for i in dates_list:
    print(i)

dates_generator = yield_dates()
print(dates_generator)
for i in dates_generator:
    print(i)

두 기능 모두 동일한 기능을 수행하지만,yield에서는 5줄 대신 3줄을 사용하며 걱정해야 할 변수가 하나 줄어듭니다.

다음은 코드의 결과입니다.

Output

보시다시피 두 기능 모두 동일한 작업을 수행합니다.유일한 차이점은return_dates()목록을 제공합니다.yield_dates()제너레이터를 제공합니다.

실제 사례는 파일을 한 줄씩 읽거나 생성기를 만들고자 하는 경우와 같습니다.

yield키워드는 단순히 반환 결과를 수집합니다.을 생각하다yield맘에 들다return +=

yield함수의 반환 요소와 같습니다.다른 점은, 그것이yield요소는 함수를 생성기로 변환합니다.생성기는 어떤 것이 '양'될 때까지 함수와 똑같이 작동합니다.제너레이터는 다음에 호출될 때까지 중지되고 시작된 것과 정확히 동일한 지점에서 계속됩니다.다음을 호출하여 모든 '양보된' 값의 시퀀스를 하나로 얻을 수 있습니다.list(generator()).

언급URL : https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python

반응형