Python 고급 특성의 생 성기

5865 단어
목록 생 성 식 을 통 해 우 리 는 목록 을 직접 만 들 수 있 지만 메모리 제한 을 받 아 목록 의 용량 이 유한 할 것 입 니 다. 그리고 100 만 개의 요 소 를 포함 하 는 목록 을 만 들 면 큰 저장 공간 을 차지 할 뿐만 아니 라 우리 가 앞의 몇 개의 요소 만 방문 해 야 한다 면 뒤의 절대 다수의 요소 가 차지 하 는 공간 은 헛되이 낭비 되 었 습 니 다.따라서 목록 요 소 를 특정한 알고리즘 에 따라 계산 할 수 있다 면 우 리 는 순환 하 는 과정 에서 후속 요 소 를 계속 계산 할 수 있 습 니까?이렇게 하면 완전한 list 를 만 들 필요 가 없고 대량의 공간 을 절약 할 수 있 습 니 다. Python 에서 순환 하면 서 계산 하 는 메커니즘 을 생 성기, generator 라 고 합 니 다.generator 를 만 들 려 면 여러 가지 방법 이 있 습 니 다.첫 번 째 방법 은 간단 합 니 다. 목록 생 성 식 [] 을 () 로 바 꾸 면 generator 를 만 듭 니 다.
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
 at 0x1022ef630>

L 과 g 를 만 드 는 차 이 는 가장 바깥쪽 [] 과 () 에 있 습 니 다. L 은 list 이 고 g 는 generator 입 니 다.우 리 는 list 의 모든 요 소 를 직접 인쇄 할 수 있 지만, generator 의 모든 요 소 를 어떻게 인쇄 합 니까?인쇄 하려 면 next() 함수 로 generator 의 다음 반환 값 을 얻 을 수 있 습 니 다.
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
Traceback (most recent call last):
  File "", line 1, in 
StopIteration

우리 가 말 했 듯 이 generator 는 알고리즘 을 저장 하고 호출 next(g) 할 때마다 g 의 다음 요소 의 값 을 계산 합 니 다. 마지막 요소 까지 계산 하고 더 많은 요소 가 없 을 때 StopIteration 의 오 류 를 던 집 니 다.물론 위의 이러한 끊 임 없 는 호출 next(g) 은 너무 변태 적 이다. 정확 한 방법 은 for 순환 이다. 왜냐하면 generator 도 교체 대상 이기 때문이다.
>>> g = (x * x for x in range(10))
>>> for n in g:
...     print(n)
...
0
1
4
9
16
25
36
49
64
81

그래서 우 리 는 generator 를 만 든 후에 기본적으로 next() 호출 되 지 않 고 for 순환 을 통 해 교체 되 며 stopIteration 의 오류 에 관심 을 가 질 필요 가 없다.generator 는 매우 강력 합 니 다. 계산 알고리즘 이 가격 보다 복잡 하면 목록 생 성 식 for 순환 이 이 루어 지지 않 을 때 함수 로 도 이 루어 질 수 있 습 니 다.예 를 들 어 유명한 피 폴 라 치 수열 (Fibonacci) 은 첫 번 째 와 두 번 째 수 를 제외 하고 모든 수 를 앞의 두 숫자 에서 더 할 수 있다. 1, 1, 2, 3, 5, 8, 13, 21, 34. 피 폴 라 치 수열 은 목록 생 성 식 으로 쓸 수 없 지만 함수 로 인쇄 하기 쉽다.
def fib(max):
      n, a, b = 0, 0, 1
      while n < max:
                print(b)
                a, b = b, a + b
                n = n + 1
       return 'done'

메모, 할당 문:
a, b = b, a + b

해당:
t = (b, a+ b) #t   tuple
a = t[0]
b = t[1]

임시 변수 t 를 쓰 지 않 아 도 값 을 부여 할 수 있 습 니 다.위의 함 수 는 피 보 나치 수열 의 앞 N 개 수 를 출력 할 수 있 습 니 다:
>>> fib(6)
1
1
2
3
5
8
'done'

자세히 살 펴 보면 fib 함 수 는 실제 적 으로 피 보 나치 수열 의 추산 규칙 을 정 의 했 고 첫 번 째 요소 부터 후속 적 으로 임 의적 인 요 소 를 추산 할 수 있다. 이런 논 리 는 사실 generator 와 매우 유사 하 다.즉, 위의 함수 와 generator 는 한 걸음 거리 에 있 습 니 다. fib 함 수 를 generator 로 바 꾸 려 면 print (b) 를 yield b 로 바 꾸 면 됩 니 다.
def fib (max):
      n, a, b = 0, 0, 1
      while n < max :
                yield b
                a, b = b, a + b
                n = n + 1
       return 'done'

이것 이 바로 generator 를 정의 하 는 또 다른 방법 이다.함수 정의 에 yield 키 워드 를 포함 하면 이 함 수 는 일반 함수 가 아니 라 generator 입 니 다.
>>> f = fib(6)
>>> f


여기 서 가장 이해 하기 어 려 운 것 은 generator 와 함수 의 집행 절차 가 다르다 는 것 이다.함 수 는 순서대로 실행 되 며, return 문장 이나 마지막 줄 의 함수 문장 을 만나면 되 돌아 갑 니 다.generator 의 함수 가 되 어 next () 를 호출 할 때마다 실 행 됩 니 다. yield 문 구 를 만 나 다시 실 행 될 때 마지막 으로 돌아 온 yield 문 구 를 계속 실행 합 니 다.간단 한 예 를 들 어 generator 를 정의 하고 숫자 1, 3, 5 를 순서대로 되 돌려 줍 니 다.
def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)

이 generator 를 호출 할 때 먼저 generator 대상 을 만 든 다음 next () 함수 로 다음 반환 값 을 계속 얻 습 니 다.
>>> o = odd()
>>> next(o)
step 1
1
>>> next(o)
step 2
3
>>> next(o)
step 3
5
>>> next(o)
Traceback (most recent call last):
  File "", line 1, in 
StopIteration

이 를 통 해 알 수 있 듯 이 odd 는 일반 함수 가 아니 라 generator 입 니 다. 실행 과정 에서 yield 를 만나면 중단 되 고 다음 에 계속 실행 되 며 3 번 yield 를 실행 한 후에 yield 가 실행 할 수 없 기 때문에 4 번 째 호출 next (o) 가 잘못 되 었 습 니 다.fib 의 예 로 돌아 가면 우 리 는 순환 과정 에서 yield 를 계속 호출 하면 계속 중단 되 고 순환 에 조건 을 설정 하여 순환 을 종료 해 야 합 니 다. 예 를 들 어 무한 수열 이 생 길 수 있 습 니 다.마찬가지 로 함 수 를 generator 로 바 꾼 후에 우 리 는 기본 적 인 뽕나무 는 next () 로 다음 반환 값 을 얻 지 않 고 for 순환 으로 교체 합 니 다.
>>> for n in fib(6):
...     print(n)
...
1
1
2
3
5
8

그러나 for 순환 으로 generator 를 호출 할 때 generator 의 return 문장의 반환 값 을 가 져 올 수 없습니다.반환 값 을 받 으 려 면 StopIteration 오 류 를 포착 해 야 합 니 다. 반환 값 은 StopIteration 의 value 에 포함 되 어 있 습 니 다.
>>> g = fib(6)
>>> while True:
...     try:
...         x = next(g)
...         print('g:', x)
...     except StopIteration as e:
...         print('Generator return value:', e.value)
...         break
...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done

소결: generator 는 매우 강력 한 도구 입 니 다. Python 에서 목록 생 성 식 을 generator 로 간단하게 바 꿀 수 있 고 함수 로 복잡 한 논 리 를 실현 할 수 있 는 generator 입 니 다.generator 의 작업 원 리 를 이해 하려 면 for 순환 과정 에서 다음 요 소 를 계속 계산 하고 적당 한 조건 에서 for 순환 을 끝 냅 니 다. 함수 가 변 경 된 generator 에 게 return 문 구 를 만 나 거나 함수 체 의 마지막 줄 문 구 를 실행 하 는 것 은 generator 의 명령 을 끝 내 는 것 입 니 다. for 순환 은 이에 따라 끝 납 니 다.일반 함수 와 generator 함 수 를 구분 하 십시오. 일반 함수 호출 은 결 과 를 직접 되 돌려 줍 니 다.
>>> r = abs(6)
>>> r
6

generator 함수 의 "호출" 은 실제 generator 대상 을 되 돌려 줍 니 다:
>>> g = fib(6)
>>> g

좋은 웹페이지 즐겨찾기