2011-11-16 2 views
1

제 발전기의 다음 두 정의 사이에서 결정하려고합니다. 어떤게 더 좋아? 어느 쪽이 "더 파이썬"인가? 그리고 어쨌든 각각의 단점을 완화 할 것입니까?파이썬 생성기 - 마지막 결과를 변경 하시겠습니까?

def myGenerator1(howMany): 
    result = [0,0,0] 
    yield result 
    for i in range(howMany) 
     modifyListInPlace(result) 
     yield result 

for val in myGenerator1(1000): 
    useValThenForgetIt(val) 

def myGenerator2(howMany): 
    result = (0,0,0) 
    yield result 
    for i in range(howMany) 
     result = createNewUpdatedTuple(result) 
     yield result 

for val in myGenerator2(1000): 
    useValThenForgetIt(val) 

첫 번째 것은 생성기에 의해 반환 된 값을 수정합니다. 아직 예상하지 못한 호출 코드로 엉망이 될 수 있습니다. 두 번째는이 경우 1000 개의 튜플을 생성합니다. "howMany"를 늘리면 더 많은 양의 쓰레기가 생성됩니다.

내가 예로 든 루프는 현재 나의 발전기를 사용하는 것입니다. do not do 나는 그것에서 나오는 값을 저장 하겠지만 다른 곳에서는 유용 할 수있는 약간의 유틸리티이다.

+0

"쓰레기"가 성능에 미치는 영향이 걱정된다면 ** 성능을 테스트하십시오 **. –

+0

좋은 지적. 필자는 성능에 대해 특별히 관심이 없으며, 그런 디자인이 좋은 연습인지, 눈살을 찌푸린 지에 대한 지침을 찾고있다. –

+0

@ 레이몬드는 건설적인 대답을 위해 대단히 감사합니다. 심지어 바보 같은 질문입니다. 나는 여전히 파이썬 놈이므로 내 길을 찾아 냈다. itertools에 대한 링크를 따라 가면서 itertools.product ([[0,1,2]] * 3)를 찾고 있습니다.하지만 다른 튜플을 반환한다는 것을 알면 유익합니다. –

답변

3

가이드로 표준 라이브러리를 살펴보면, itertools 모듈의 조합 함수는 기본 알고리즘이 mutate-in-place 알고리즘이지만 모든 튜플을 반환합니다. 예를 들어 itertools.permutations의 코드를 살펴보십시오.

이 디자인 (목록 대신 튜플을 반환)은 견고 함이 입증되었습니다. 돌연변이리스트 접근법은 호출자가 반복자의 반환 값을 가지고 무엇을하는지에 따라 찾기 힘든 버그를 만들어 낼까 걱정됩니다.

다른 생각. 사용하지 않은 결과에 대해 "쓰레기 중 가치있는 튜플을 만드는"것에 대해서는별로 걱정하지 않을 것입니다. 파이썬의 튜플 구현은 이전에 폐기 된 튜플을 재사용 할 때 매우 유용합니다 (프리리스트 배열을 사용하여 메모리 할당자를 호출하지 않고 이전에 사용 된 튜플을 새로 만들 수 있음). 따라서 튜플 버전은 목록 버전 또는 약간 더 나은 성능을 제공합니다.

+0

내가 심지어 실현하는 건설적인 대답에 대해 대단히 감사합니다. 바보 같은 질문입니다. 나는 여전히 파이썬 놈이므로 내 길을 찾아 냈다. itertools에 대한 링크를 따라 가면서 itertools.product ([[0,1,2]] * 3)를 찾고 있습니다.하지만 다른 튜플을 반환한다는 것을 알면 유익합니다. –

1

첫 번째 객체가 객체를 반환 할 수 있고 반환 된 후에 명백하게 수정하지 못한다는 사실은 사용하는 언어에 상관없이 나에게 거대한 코드 냄새가됩니다 (즉, pythonic "). 또한, 왜 동일한 값에 대한 반복자를 반복적으로 생성하고 yield간에 수정하는 함수를 원하십니까? 나에게 매우 직관적이지 않은 것 같습니다.

값을 사용하면 myGenerator2에 의해 생성 된 튜플은 가비지가 아닙니다. 한 번에 하나씩 사용하면 동시에 존재할 수 없으며 프로그램은 다른 많은 메모리 할당/할당 해제를 수행 할 것입니다. range(howMany)이 반환하는 목록과는 달리 입니다. 실제로 사용하지 않는 1,000 개의 정수를 만듭니다 (Python3을 사용하지 않는 한 range은 목록이 아닌 생성기를 반환 함).

어떤 기회가 전혀 발신자가 발전기에 의해 반환 뭔가에 대한 참조에 정지 할 수 있다면 발전기를 제공 할 때 (그리고 파이썬 프로그래머는 일반적으로 예상, 그들이 필요로하는 경우 items = list(generator)을 갈 수있을 것 두 번 이상 사용하는 경우), 두 번째가 훨씬 우수합니다.

+0

왜?"digit"(trigits?)를 목록으로 색인으로 사용하여 base3을 계산하면 결과가 완료됩니다. 내가 itertools.product ([[0,1,2]] * 3)를 찾고 있습니다. –

+0

@Mike 놀랍지 만 놀라움으로 인해 버그가 발생합니다. 파이썬 프로그래머는 생성자 인 경우 입력을 소비하는 것 이외에 부작용이있는 것을 반복하는 것을 기대하지 않습니다. 발전기의 호출자를 구현과 더 긴밀하게 연결합니다. 발신자는 원하는 것을 무엇이든 할 수 없다는 것을 알고 있어야합니다. 프로그래머가 디버깅에 걸리는 시간과 실제 작업에서 발생하는 버그는 거의 모든 상황에서 작은 성능 손실보다 비용이 많이 듭니다. – Ben

관련 문제