English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
이 문서에서는 파이썬 생성자를 사용하여 이터레이션을 쉽게 생성하는 방법을 배우고, 이터레이터와 일반 함수와의 차이점, 그리고 왜 사용하는지에 대해 배울 것입니다.
파이썬으로구축이터레이터빈도가 높습니다. 우리는 __iter__()와 __next__() 메서드를 사용하여 클래스를 구현해야 하며, 반환할 값이 없을 때 StopIteration을 발생시키는 등의 작업을 수행해야 합니다.
이는 긴장적이고 통찰력을 떨어뜨립니다. 이 경우 생성자가 유용할 수 있습니다.
파이썬 생성자는 이터레이터를 생성하는 간단한 방법입니다. 우리가 언급한 모든 비용은 파이썬 생성자가 자동으로 처리합니다.
간단히 말해, 생성자는 함수입니다. 이는 객체(이터레이터)를 반환하며, 우리는 이를 순회할 수 있습니다(한 번에 하나의 값).
파이썬에서 생성자를 생성하는 것은 매우 간단합니다. 일반 함수와 마찬가지로 yield 문을 사용하여 정의하는 것과 같습니다.
한 함수가 최소한 하나의 yield 문(다른 yield나 return 문을 포함할 수 있습니다)을 포함하면 그 함수는 생성자 함수가 됩니다. yield와 return은 모두 함수에서 값을 반환합니다.
차이점은 return 문이 함수를 완전히 종료할 때, yield 문은 함수를 일시적으로 중지하고 모든 상태를 저장하여 후속 호출에서 계속 실행되도록 합니다.
이는 생성자 함수와일반 함수의차이점.
생성자 함수는 하나 이상의 yield 문을 포함합니다.
호출 시, 이는 객체(이터레이터)를 반환하지만 즉시 실행되지 않습니다.
__iter__()와 __next__()와 같은 메서드는 자동으로 구현됩니다. 따라서 next()를 사용하여 항목을 순회할 수 있습니다.
함수가 결과를 생성하면 함수는 중지되고, 컨트롤이 호출자에게 전달됩니다.
지역 변수와 그 상태는 연속 호출 사이에 기억됩니다.
마지막으로, 함수가 종료될 때 추가 호출 시 자동으로 StopIteration이 발생합니다.
이는 위의 모든 주제를 설명하는 예제입니다. 우리는 yield 문으로 이름 지정된 my_gen() 생성자 함수를 가지고 있습니다.
# 간단한 제너레이터 함수 def my_gen(): n = 1 print('이것은 첫 번째 출력입니다') # yield 문을 포함한 제너레이터 함수 yield n n += 1 print('이것은 두 번째 출력입니다') yield n n += 1 print('이것은 마지막 출력입니다') yield n
인터프리터에서의 상호작용 실행은 다음과 같습니다. 파이썬 셸에서 이 명령어를 실행하여 출력을 확인하세요.
>>> # 이는 객체를 반환하지만 즉시 실행되지 않습니다. >>> a = my_gen() >>> # 이들 항목을 next()를 사용하여 이터네이트할 수 있습니다. >>> next(a) 이것은 첫 번째 출력입니다 1 >>> # 함수가 결과를 생성하면 함수는 일시적으로 중단되고, 컨트롤이 호출자에게 이전됩니다. >>> # 지역 변수 및 상태는 연속 호출 사이에 기억됩니다. >>> next(a) 이것은 두 번째 출력입니다 2 >>> next(a) 이것은 마지막 출력입니다 3 >>> # 함수가 종료될 때, 추가 호출 시 자동으로 StopIteration이 발생합니다. >>> next(a) Traceback (최근 호출이 마지막): ... StopIteration >>> next(a) Traceback (최근 호출이 마지막): ... StopIteration
위의 예제에서 주목할 만한 것은, 매번 호출 사이에 변수가 기억된다는 것입니다.n의 값.
일반 함수와 달리, 지역 변수는 함수가 생성될 때 파괴되지 않습니다. 또한, 제너레이터 객체는 한 번만 이터네이트할 수 있습니다.
이 과정을 다시 시작하려면 = my_gen()와 같은 것을 사용하여 다른 제너레이터 객체를 생성해야 합니다.
주의:마지막으로 주의해야 할 것은, 제너레이터를 직접for 루프함께 사용.
이유는, for 루프는 이터레이터를 받아들이고, next() 함수를 사용하여 이터레이터를 이터네이트합니다. StopIteration이 발생하면 자동으로 종료됩니다.Python에서 for 루프를 실제로 구현하는 방법을 이해해보겠습니다..
# 간단한 제너레이터 함수 def my_gen(): n = 1 print('이것은 첫 번째 출력입니다') # yield 문을 포함한 제너레이터 함수 yield n n += 1 print('이것은 두 번째 출력입니다') yield n n += 1 print('이것은 마지막 출력입니다') yield n # for 루프 사용 for item in my_gen(): print(item)
프로그램을 실행할 때, 출력은 다음과 같습니다:
이것은 첫 번째 출력입니다 1 이것은 두 번째 출력입니다 2 이것은 마지막 출력입니다 3
위의 예제는 크게 유용하지 않지만, 배경에서 일어나는 일을 이해하기 위해 연구했습니다.
보통, 제너레이터 함수는 적절한 종료 조건을 가진 루프를 통해 구현됩니다.
문자열을 반대로 돌리는 제너레이터 예제를 보겠습니다.
def rev_str(my_str): length = len(my_str) for i in range(length - 1,-1,-1) yield my_str[i] # 문자열을 반대로 돌리는 for 루프 # 출력: # o # l # l # e # h for char in rev_str("hello"): print(char)
이 예제에서는 range() 함수를 사용하여 for 루프를 반대로 순서로 인덱스를 가져오는 방법을 사용합니다.
실제로 이 생성자 함수는 문자열뿐만 아니라 다른 종류의 이터러블 객체, 예를 들어}}list,tuple와 같습니다.
생성자 표현식을 사용하면 간단한 생성자를 동적으로 생성할 수 있으며, 생성자를 만들어내는 데 편리합니다.
lambda 함수와 생성됩니다익명 함수와 동일합니다와 유사합니다.
생성자 표현식의 문법은 다음과 같습니다.Python의리스트 이해문법. 하지만 괄호를 대괄호로 대체합니다.
리스트 이해와 생성자 표현식 간의 주요 차이점은, 리스트 이해는 전체 리스트를 생성하지만, 생성자 표현식은 한 번에 하나의 아이템을 생성한다는 점입니다.
그들은 조금 가볍고, 필요할 때에만 아이템을 생성합니다. 이 이유로, 생성자 표현식은 동일한 리스트 이해와 비교하여内存 효율성이 훨씬 높습니다.
# 리스트 초기화 my_list = [1, 3, 6, 10] # 각 항목에 대해 제곱을 계산하는 리스트 이해 # 출력: [1, 9, 36, 100] [x**2 for x in my_list] # 같은 일을 생성자 표현식으로도 할 수 있습니다 # 출력: <generator object <genexpr> at 0x000000000>2EBDAF8> (x**2 for x in my_list)
위에서 보면 생성자 표현식은 즉시 필요한 결과를 생성하지 않습니다. 대신, 생성자 객체를 반환하며, 이 객체는 필요에 따라 생성되는 아이템을 가지고 있습니다.
# 리스트 초기화 my_list = [1, 3, 6, 10] a = (x**2 for x in my_list) # 출력: 1 print(next(a)) # 출력: 9 print(next(a)) # 출력: 36 print(next(a)) # 출력: 100 print(next(a)) # 출력: StopIteration next(a)
generator 표현식은 함수 내에서 사용할 수 있습니다. 이렇게 사용할 때는 괄호를 제거할 수 있습니다.
>>> sum(x**2 for x in my_list) 146 >>> max(x**2 for x in my_list) 100
generator가 유용한 구현이 되는 이유가 몇 가지 있습니다.
그들의 이터레이터 클래스 항목과 대응하여, 생성자는 명확하고 간결한 방식으로 구현할 수 있습니다. 아래는 iterator 클래스를 사용하여 구현된 예제입니다.2의 권한 시퀀스 예제.
class PowTwo: def __init__(self, max = 0): self.max = max def __iter__(self): self.n = 0 return self def __next__(self): if self.n > self.max: raise StopIteration result = 2 ** self.n self.n += 1 return result
이 코드는 매우 길다. 지금, 제너레이터 함수를 사용하여 동일한 작업을 수행하겠습니다.
def PowTwoGen(max = 0): n = 0 while n < max: yield 2 ** n n += 1
제너레이터는 자동으로 세부 사항을 추적하기 때문에 간결하고, 구현도 간결합니다.
일반적인 시퀀스를 반환하는 함수는 결과를 반환하기 전에 메모리에 전체 시퀀스를 생성합니다. 시퀀스 항목의 수가 많으면 효율성에 영향을 미칩니다.
이러한 시퀀스의 제너레이터 구현은 메모리에 유리하여 최선입니다. 왜냐하면 한 번에 한 항목만 생성하기 때문입니다.
제너레이터는 무한 데이터 흐름을 표현하는 최적의 도구입니다. 무한 흐름은 메모리에 저장할 수 없으며, 제너레이터는 한 번에 한 항목만 생성하기 때문에 무한 데이터 흐름을 표현할 수 있습니다.
다음 예제는 모든 짝수를 생성할 수 있습니다.(이론적으로는).
def all_even(): n = 0 while True: yield n n += 2
제너레이터는 일련의 작업을 배관화할 수 있습니다. 예제를 통해 설명하겠습니다.
유명한 패스트 푸드 체인의 로그 파일이 있습니다. 로그 파일에는 열이 있습니다.4열), 이 열은 매시간 판매된 피자의 수를 추적하고, 이를 합쳐서5년간 판매된 피자의 총 수.
모든 내용이 문자열이고, 사용할 수 있는 숫자가 없으면 'N'으로 표시됩니다. / A. 제너레이터 구현은 다음과 같습니다.
with open('sells.log') as file: pizza_col = (line[3] for line in file) per_hour = (int(x) for x in pizza_col if x != 'N/A') print("총 판매 피자 수 = ", sum(per_hour))
이 배관은 매우 효율적이고 읽기 쉽습니다. (네, 정말 멋지죠!).