반복자와 생성기의 차이점은 무엇입니까? 각 사례를 언제 사용할 것인지에 대한 몇 가지 예가 도움이 될 것입니다.
답변
iterator
보다 일반적인 개념입니다. 클래스에 next
메소드 ( __next__
Python 3)와 그 __iter__
메소드 가있는 객체입니다 return self
.
모든 생성기는 반복자이지만 그 반대는 아닙니다. 제너레이터는 하나 이상의 yield
표현식 ( yield
Python 2.5 및 이전 버전의 명령문) 이있는 함수를 호출하여 빌드되며 이전 단락의의 정의를 충족시키는 객체입니다 iterator
.
상태 유지가 다소 복잡한 클래스가 필요하거나 next
(and __iter__
및 __init__
) 이외의 다른 메소드를 노출하려는 경우 생성기 대신 사용자 정의 반복자를 사용하려고 할 수 있습니다 . 대부분의 경우 제너레이터 (때로는 충분히 간단한 요구, 제너레이터 표현식 )로 충분하며 상태 유지 (합당한 한계 내)가 기본적으로 프레임이 일시 중지되고 재개 됨으로써 “완료”되기 때문에 코딩이 더 간단합니다.
예를 들어 다음과 같은 생성기 :
def squares(start, stop):
for i in range(start, stop):
yield i * i
generator = squares(a, b)
또는 등가 생성기 표현식 (genexp)
generator = (i*i for i in range(a, b))
사용자 정의 반복자로 빌드하려면 더 많은 코드가 필요합니다.
class Squares(object):
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __iter__(self): return self
def next(self): # __next__ in Python 3
if self.start >= self.stop:
raise StopIteration
current = self.start * self.start
self.start += 1
return current
iterator = Squares(a, b)
그러나 물론 수업을 통해 Squares
추가 방법을 쉽게 제공 할 수 있습니다.
def current(self):
return self.start
응용 프로그램에서 이러한 추가 기능이 실제로 필요한 경우.
답변
반복자와 생성기의 차이점은 무엇입니까? 각 사례를 언제 사용할 것인지에 대한 몇 가지 예가 도움이 될 것입니다.
요약 : 반복자는이 개체 __iter__
와을 __next__
( next
파이썬 2) 방법. 생성기는 반복기 인스턴스를 작성하는 쉽고 내장 된 방법을 제공합니다.
yield가있는 함수는 여전히 호출되는 경우 생성기 객체의 인스턴스를 반환하는 함수입니다.
def a_function():
"when called, returns generator object"
yield
생성기 표현식은 또한 생성기를 반환합니다.
a_generator = (i for i in range(0))
보다 심층적 인 설명과 예제를 보려면 계속 읽으십시오.
생성기 는 반복자입니다
특히 generator는 이터레이터의 하위 유형입니다.
>>> import collections, types
>>> issubclass(types.GeneratorType, collections.Iterator)
True
몇 가지 방법으로 생성기를 만들 수 있습니다. 가장 일반적이고 간단한 방법은 함수를 사용하는 것입니다.
특히 수율이있는 함수는 호출되면 생성기를 반환하는 함수입니다.
>>> def a_function():
"just a function definition with yield in it"
yield
>>> type(a_function)
<class 'function'>
>>> a_generator = a_function() # when called
>>> type(a_generator) # returns a generator
<class 'generator'>
그리고 생성기는 다시 반복자입니다.
>>> isinstance(a_generator, collections.Iterator)
True
반복자 는 반복 가능
Iterator는 Iterable입니다.
>>> issubclass(collections.Iterator, collections.Iterable)
True
__iter__
반복자를 반환 하는 메소드가 필요합니다 .
>>> collections.Iterable()
Traceback (most recent call last):
File "<pyshell#79>", line 1, in <module>
collections.Iterable()
TypeError: Can't instantiate abstract class Iterable with abstract methods __iter__
iterables의 몇 가지 예는 내장 튜플, 목록, 사전, 세트, 고정 된 세트, 문자열, 바이트 문자열, 바이트 배열, 범위 및 메모리 뷰입니다.
>>> all(isinstance(element, collections.Iterable) for element in (
(), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
True
반복자 에는next
또는 __next__
메소드가 필요 합니다
파이썬 2에서 :
>>> collections.Iterator()
Traceback (most recent call last):
File "<pyshell#80>", line 1, in <module>
collections.Iterator()
TypeError: Can't instantiate abstract class Iterator with abstract methods next
그리고 파이썬 3에서 :
>>> collections.Iterator()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Iterator with abstract methods __next__
다음 iter
함수 를 사용하여 내장 객체 (또는 사용자 정의 객체)에서 반복자를 가져올 수 있습니다 .
>>> all(isinstance(iter(element), collections.Iterator) for element in (
(), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
True
__iter__
당신이에 대한 루프와 객체를 사용하려고하면 메서드가 호출됩니다. 그런 다음 __next__
반복자 객체 에서 메소드를 호출하여 루프에 대한 각 항목을 가져옵니다. 반복기가 StopIteration
소진되면 올라가고 그 시점에서 재사용 할 수 없습니다.
설명서에서
내장 유형 문서 의 반복자 유형 섹션의 생성기 유형 섹션에서 다음을 수행하십시오 .
파이썬의 생성기는 반복기 프로토콜을 구현하는 편리한 방법을 제공합니다. 컨테이너 객체의
__iter__()
메소드가 생성자로 구현되면,__iter__()
그리고next()
[__next__()
in Python 3] 메소드를 제공하는 반복자 객체 (기술적으로 생성기 객체)를 자동으로 반환합니다 . 생성기에 대한 자세한 내용은 생산량 표현 설명서를 참조하십시오.
(공포도 추가됨)
이것으로부터 우리는 Generators가 (편리한) Iterator 유형이라는 것을 알게됩니다.
반복자 객체 예
자신의 객체를 만들거나 확장하여 Iterator 프로토콜을 구현하는 객체를 만들 수 있습니다.
class Yes(collections.Iterator):
def __init__(self, stop):
self.x = 0
self.stop = stop
def __iter__(self):
return self
def next(self):
if self.x < self.stop:
self.x += 1
return 'yes'
else:
# Iterators must raise when done, else considered broken
raise StopIteration
__next__ = next # Python 3 compatibility
그러나 간단히 Generator를 사용하여이 작업을 수행하는 것이 더 쉽습니다.
def yes(stop):
for _ in range(stop):
yield 'yes'
또는 더 간단한 생성기 표현식 (목록 이해와 비슷하게 작동) :
yes_expr = ('yes' for _ in range(stop))
그것들은 모두 같은 방식으로 사용될 수 있습니다 :
>>> stop = 4
>>> for i, y1, y2, y3 in zip(range(stop), Yes(stop), yes(stop),
('yes' for _ in range(stop))):
... print('{0}: {1} == {2} == {3}'.format(i, y1, y2, y3))
...
0: yes == yes == yes
1: yes == yes == yes
2: yes == yes == yes
3: yes == yes == yes
결론
반복 가능한 객체로 Python 객체를 확장해야 할 때 Iterator 프로토콜을 직접 사용할 수 있습니다.
그러나 대부분의 경우 yield
Generator Iterator를 반환하거나 Generator Expressions를 고려하는 함수를 정의하는 데 가장 적합합니다 .
마지막으로 생성기는 코 루틴으로 훨씬 더 많은 기능을 제공합니다. ‘제작’키워드의 기능은 무엇입니까? ‘에 대한 답변에 대한 설명과 함께 생성기를 설명 yield
합니다.
답변
반복자 :
반복자는 next()
방법을 사용 하여 다음 순서 값을 얻는 객체입니다 .
발전기 :
제너레이터는 yield
방법을 사용하여 일련의 값을 생성하거나 생성하는 함수입니다 .
제너레이터 함수 (예 : 아래 예제의 함수)에서 반환 된 next()
제너레이터 객체 (예 : f
아래 예제의 경우)에 대한 모든 메서드 호출은 foo()
다음 값을 순서대로 생성합니다.
생성기 함수가 호출되면 함수 실행을 시작하지 않고도 생성기 객체를 반환합니다. next()
메소드가 처음으로 호출 되면 함수는 yield 문에 도달 할 때까지 실행을 시작하여 yield 값을 리턴합니다. 수율은 마지막 실행을 기억합니다. 그리고 두 번째 next()
호출은 이전 값에서 계속됩니다.
다음 예제는 생성기 객체에서 yield와 next 메소드 호출 간의 상호 작용을 보여줍니다.
>>> def foo():
... print "begin"
... for i in range(3):
... print "before yield", i
... yield i
... print "after yield", i
... print "end"
...
>>> f = foo()
>>> f.next()
begin
before yield 0 # Control is in for loop
0
>>> f.next()
after yield 0
before yield 1 # Continue for loop
1
>>> f.next()
after yield 1
before yield 2
2
>>> f.next()
after yield 2
end
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
답변
기존 답변이 공식 문헌의 혼동을 구체적으로 다루지 않으므로 답변 추가
생성기 함수 는yield
대신에정의 된 일반 함수입니다return
. 제너레이터 함수가 호출되면 제너레이터 객체를 반환합니다. 제너레이터 객체 는next()
메소드입니다. 를 호출next()
하면 생성기 함수에서 생성 된 다음 값이 반환됩니다.
읽은 Python 소스 문서에 따라 함수 또는 객체를 “제너레이터”라고 할 수 있습니다. 파이썬 용어는 그동안, 발전기 기능을 말한다 파이썬 위키가 발생 개체를 의미한다. 파이썬 튜토리얼은 현저하게 암시하는 관리 두 세 문장의 공간에서 용도를 :
제너레이터는 이터레이터를 만드는 간단하고 강력한 도구입니다. 그것들은 일반 함수처럼 작성되지만 데이터를 반환하려고 할 때마다 yield 문을 사용합니다. next ()가 호출 될 때마다 생성기는 중단 된 위치에서 재개합니다 (모든 데이터 값과 마지막으로 실행 된 명령문을 기억합니다).
처음 두 문장은 생성기 기능이있는 생성기를 식별하고 세 번째 문장은 생성기 객체로 식별합니다.
이 모든 혼란에도 불구하고 , 명확하고 최종 단어에 대한 파이썬 언어 참조 를 찾을 수 있습니다 .
yield 표현식은 생성기 함수를 정의 할 때만 사용되며 함수 정의 본문에서만 사용할 수 있습니다. 함수 정의에서 yield 표현식을 사용하면 해당 정의가 일반 함수 대신 생성기 함수를 작성하기에 충분합니다.
생성기 함수가 호출되면 생성기라는 반복기를 반환합니다. 그런 다음 해당 생성기는 생성기 기능의 실행을 제어합니다.
따라서 공식적이고 정확한 사용법에서 “제너레이터”비 한정자는 생성기 기능이 아닌 생성기 객체를 의미합니다.
위의 참조는 Python 2에 대한 것이지만 Python 3 언어 참조 는 같은 것을 말합니다. 그러나 파이썬 3 용어 는
generator … 일반적으로 생성기 기능을 나타내지 만 일부 상황에서는 생성기 반복기를 나타낼 수도 있습니다. 의도 된 의미가 명확하지 않은 경우 전체 용어를 사용하면 모호성을 피할 수 있습니다.
답변
모든 사람들은 예제를 통해 정말 훌륭하고 자세한 답변을 얻었으며 정말 감사합니다. 나는 여전히 개념적으로 명확하지 않은 사람들을 위해 짧은 몇 줄의 답변을주고 싶었습니다.
자신 만의 반복자를 만들면 약간 복잡합니다. 클래스를 만들고 최소한 iter와 다음 메소드를 구현해야합니다. 그러나이 번거 로움을 피하고 반복기를 빠르게 만들고 싶다면 어떻게해야합니까? 다행스럽게도 파이썬은 반복자를 정의하는 지름길을 제공합니다. 적어도 한 번의 호출로 함수를 정의하기 만하면됩니다. 이제 해당 함수를 호출 하면 반복자처럼 작동하는 ” 뭔가 “를 반환 합니다 (다음 메소드를 호출하고 for 루프에서 사용할 수 있음). 이 일이 생성기라는 파이썬에서 이름이
그것이 조금 명확 해지기를 바랍니다.
답변
이전 답변은이 추가 사항을 놓쳤습니다. 제너레이터에는 close
메소드가 있지만 일반적인 반복자는 그렇지 않습니다. 이 close
메소드 StopIteration
는 생성기에서 예외를 트리거합니다 .finally
해당 반복기 절에서 정리를 실행할 기회를 얻습니다. 이 추상화는 단순한 반복자보다 대규모에서 가장 유용합니다. 파일을 닫을 수 있으므로 생성기를 닫을 수 있습니다. 파일을 닫을 필요가 없습니다.
즉, 첫 번째 질문에 대한 나의 개인적인 대답은 : iteratable에는 __iter__
메소드 만 있고, 전형적인 반복자는 __next__
메소드 만 있고, 제너레이터에는 __iter__
a __next__
와 a 및 추가가 close
있습니다.
두 번째 질문에 대해 내 개인 응답은 다음과 같습니다 더 탄력 이후 공용 인터페이스에, 나는 발전기를 많이 선호하는 경향이 다음 close
의 메소드와 더 큰의 조합 성을 yield from
. 로컬에서는 반복자를 사용할 수 있지만 평평하고 간단한 구조 (반복기가 쉽게 구성되지 않음)이고 시퀀스가 다소 짧을 것이라고 생각할만한 이유가있는 경우에만 특히 시퀀스가 끝나기 전에 중지 될 수 있습니다. 리터럴을 제외하고 반복자를 낮은 수준의 프리미티브로 보는 경향이 있습니다.
제어 흐름 문제의 경우 생성기는 약속만큼이나 중요한 개념입니다. 둘 다 추상적이며 구성 가능합니다.
답변
발전기 기능, 발전기 객체, 발전기 :
발전기 기능은 파이썬에서 정규 기능처럼이지만 하나 이상 포함되어 yield
문을. 생성기 함수는 Iterator 객체를 가능한 한 쉽게 만들 수있는 훌륭한 도구 입니다. 반복자 생성 기능에 의해 오브젝트 returend도 불린다 생성기 객체 또는 발전기 .
이 예제에서는 Generator 객체를 반환하는 Generator 함수를 만들었습니다 <generator object fib at 0x01342480>
. 다른 반복자와 마찬가지로 Generator 객체는 for
루프에서 또는 내장 함수 next()
를 사용하여 생성기에서 다음 값을 반환 할 수 있습니다.
def fib(max):
a, b = 0, 1
for i in range(max):
yield a
a, b = b, a + b
print(fib(10)) #<generator object fib at 0x01342480>
for i in fib(10):
print(i) # 0 1 1 2 3 5 8 13 21 34
print(next(myfib)) #0
print(next(myfib)) #1
print(next(myfib)) #1
print(next(myfib)) #2
따라서 생성기 함수는 Iterator 객체를 만드는 가장 쉬운 방법입니다.
반복자 :
모든 생성기 객체 는 반복자 이지만 그 반대는 아닙니다. 클래스가 구현 __iter__
하고 __next__
메소드 (반복자 프로토콜이라고도 함) 인 경우 사용자 정의 반복자 오브젝트를 작성할 수 있습니다 .
그러나, 발전기 생성하는 기능을 사용하는 것이 훨씬 쉽다 반복자를 그들의 생성을 단순화하기 때문에,하지만 사용자 정의는 반복자는 당신에게 더 많은 자유를 제공하고 아래의 예와 같이 당신은 또한 당신의 요구 사항에 따라 다른 방법을 구현할 수 있습니다.
class Fib:
def __init__(self,max):
self.current=0
self.next=1
self.max=max
self.count=0
def __iter__(self):
return self
def __next__(self):
if self.count>self.max:
raise StopIteration
else:
self.current,self.next=self.next,(self.current+self.next)
self.count+=1
return self.next-self.current
def __str__(self):
return "Generator object"
itobj=Fib(4)
print(itobj) #Generator object
for i in Fib(4):
print(i) #0 1 1 2
print(next(itobj)) #0
print(next(itobj)) #1
print(next(itobj)) #1