[python] 제너레이터를 호출하는 함수에서 리턴 또는 수율?

발전기 generator와 편리한 방법이 있습니다 generate_all.

def generator(some_list):
  for i in some_list:
    yield do_something(i)

def generate_all():
  some_list = get_the_list()
  return generator(some_list) # <-- Is this supposed to be return or yield?

할까요 generate_all return또는 yield? 두 방법을 사용하는 사용자가 동일하게 사용하기를 원합니다. 즉

for x in generate_all()

와 같아야한다

some_list = get_the_list()
for x in generate(some_list)



답변

발전기는-게으른 평가 이렇게 있습니다 return또는 yield예외가 발생하는 경우 당신은 당신의 코드를 디버깅 할 때 다르게 행동이나됩니다.

return당신에 발생하는 예외 generator에 대해 아무것도 알 수 없습니다 generate_all때 때문입니다, generator정말 실행 이미 남아있는 generate_all기능을. 함께 yield거기가있을 것이다 generate_all역 추적에.

def generator(some_list):
    for i in some_list:
        raise Exception('exception happened :-)')
        yield i

def generate_all():
    some_list = [1,2,3]
    return generator(some_list)

for item in generate_all():
    ...
Exception                                 Traceback (most recent call last)
<ipython-input-3-b19085eab3e1> in <module>
      8     return generator(some_list)
      9
---> 10 for item in generate_all():
     11     ...

<ipython-input-3-b19085eab3e1> in generator(some_list)
      1 def generator(some_list):
      2     for i in some_list:
----> 3         raise Exception('exception happened :-)')
      4         yield i
      5

Exception: exception happened :-)

그리고 그것을 사용한다면 yield from:

def generate_all():
    some_list = [1,2,3]
    yield from generator(some_list)

for item in generate_all():
    ...
Exception                                 Traceback (most recent call last)
<ipython-input-4-be322887df35> in <module>
      8     yield from generator(some_list)
      9
---> 10 for item in generate_all():
     11     ...

<ipython-input-4-be322887df35> in generate_all()
      6 def generate_all():
      7     some_list = [1,2,3]
----> 8     yield from generator(some_list)
      9
     10 for item in generate_all():

<ipython-input-4-be322887df35> in generator(some_list)
      1 def generator(some_list):
      2     for i in some_list:
----> 3         raise Exception('exception happened :-)')
      4         yield i
      5

Exception: exception happened :-)

그러나 이는 성능 저하를 초래합니다. 추가 생성기 레이어에는 약간의 오버 헤드가 있습니다. 따라서 return일반적으로 yield from ...(또는 for item in ...: yield item) 보다 약간 빠릅니다 . 대부분의 경우 생성기에서 수행하는 작업이 일반적으로 런타임을 지배하므로 추가 계층이 눈에 띄지 않기 때문에 이것은 중요하지 않습니다.

그러나 yield몇 가지 추가 장점이 있습니다. 단일 iterable로 제한되지 않고 추가 항목을 쉽게 생성 할 수도 있습니다.

def generator(some_list):
    for i in some_list:
        yield i

def generate_all():
    some_list = [1,2,3]
    yield 'start'
    yield from generator(some_list)
    yield 'end'

for item in generate_all():
    print(item)
start
1
2
3
end

귀하의 경우 작업이 매우 간단하고이를 위해 여러 함수를 작성해야하는지도 모르겠습니다 map. 대신 내장 또는 생성기 표현식을 대신 사용할 수 있습니다 .

map(do_something, get_the_list())          # map
(do_something(i) for i in get_the_list())  # generator expression

둘 다 동일해야합니다 (예외가 발생할 때 약간의 차이는 제외). 그리고 그들이 더 설명적인 이름이 필요하다면, 당신은 여전히 ​​그것들을 하나의 기능으로 포장 할 수 있습니다.

iterables 빌트인에 대한 매우 일반적인 조작을 랩핑하는 여러 헬퍼가 있으며, 빌트인 itertools모듈 에서 추가 툴을 찾을 수 있습니다 . 그런 간단한 경우에 나는 단순히 이것에 의지하고 사소한 경우에만 자신의 발전기를 씁니다.

그러나 실제 코드가 더 복잡하여 적용 할 수 없을 수도 있지만 대안을 언급하지 않으면 완전한 답변이 아니라고 생각했습니다.


답변

발전기 위임 (PEP380)을 찾고 계십니까?

간단한 반복자의 경우 yield from iterable본질적으로 단축 된 형태입니다.for item in iterable: yield item

def generator(iterable):
  for i in iterable:
    yield do_something(i)

def generate_all():
  yield from generator(get_the_list())

꽤 간결하고 임의 / 다른 반복 가능 체인을 연결할 수있는 것과 같은 다른 많은 장점이 있습니다!


답변

return generator(list)당신이 원하는 것을합니다. 그러나 참고

yield from generator(list)

동일하지만, generator소진 된 후에 더 많은 가치를 산출 할 수있는 기회가 주어집니다 . 예를 들면 다음과 같습니다.

def generator_all_and_then_some():
    list = get_the_list()
    yield from generator(list)
    yield "one last thing"


답변

이 특별한 경우에 다음 두 문장은 기능적으로 동등한 것으로 보입니다.

return generator(list)

yield from generator(list)

후자는 대략

for i in generator(list):
    yield i

return명령문은 찾고있는 생성기를 리턴합니다. yield from또는 yield문은 무언가로 그 반환 당신이 찾고있는 하나를 통과 발전기를, 전체 기능을집니다.

사용자 관점에서는 차이가 없습니다. 그러나 내부적 으로 불필요한 패스 스루 생성기에 싸이 지 return않기 때문에 더 효율적 generator(list)입니다. 랩핑 된 생성기의 요소에 대한 처리 를 계획중인 경우 , 어떤 형태 yield의 과정을 사용하십시오.


답변

당신은 return그것을 할 것입니다.

yielding *을 사용하면 generate_all()생성기 자체를 평가할 수 있으며 next해당 외부 생성기를 호출 하면 첫 번째 함수에서 반환 한 내부 생성기가 반환됩니다.

* 를 포함하지 않는 yield from


답변