질문 : "yield"키워드의 기능은 무엇입니까?
yield
키워드의 사용은 무엇이며 어떤 역할을합니까?
예를 들어,이 코드 1 을 이해하려고합니다.
def _get_child_candidates(self, distance, min_dist, max_dist):
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
그리고 이것은 호출자입니다.
result, candidates = [], [self]
while candidates:
node = candidates.pop()
distance = node._get_dist(obj)
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result
_get_child_candidates
메소드가 호출되면 어떻게됩니까? 목록이 반환됩니까? 단일 요소? 또 불려? 후속 통화는 언제 중지됩니까?
1.이 코드는 메트릭 공간을위한 훌륭한 Python 라이브러리를 만든 Jochen Schulz (jrschulz)가 작성했습니다. 이것은 완전한 소스에 대한 링크입니다 : Module mspace .
답변
yield
가 무엇을하는지 이해하려면 생성기 가 무엇인지 이해해야합니다. 제너레이터를 이해하기 전에 iterable을 이해해야합니다.
목록을 만들 때 항목을 하나씩 읽을 수 있습니다. 항목을 하나씩 읽는 것을 반복이라고합니다.
>>> mylist = [1, 2, 3]
>>> for i in mylist:
... print(i)
1
2
3
mylist
는 반복 가능 합니다. 목록 이해력을 사용하면 목록이 생성되므로 반복 가능합니다.
>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
... print(i)
0
1
4
for... in...
"을 사용할 수있는 모든 것은 반복 가능합니다. lists
, strings
, 파일 ...
이러한 이터 러블은 원하는만큼 읽을 수 있기 때문에 편리하지만 모든 값을 메모리에 저장하며 값이 많을 때 항상 원하는 것은 아닙니다.
생성기는 한 번만 반복 할 수있는 일종의 반복자입니다. 생성기는 모든 값을 메모리에 저장하지 않고 즉시 값을 생성합니다 .
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
... print(i)
0
1
4
[]
대신 ()
를 사용한 것을 제외하면 동일합니다. 그러나 for i in mygenerator
두 번 수행 할 수 없습니다. 생성기는 0을 계산 한 다음 잊어 버리고 1을 계산하고 4 계산을 하나씩 종료합니다.
yield
는 함수가 생성기를 반환한다는 점을 제외하고 return
과 같이 사용되는 키워드입니다.
>>> def create_generator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
>>> mygenerator = create_generator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object create_generator at 0xb7555c34>
>>> for i in mygenerator:
... print(i)
0
1
4
여기에 쓸모없는 예가 있지만 함수가 한 번만 읽어야 할 거대한 값 집합을 반환한다는 것을 알고있을 때 편리합니다.
yield
를 마스터하려면 함수를 호출 할 때 함수 본문에 작성한 코드가 실행되지 않음을 이해해야합니다. 이 함수는 생성기 객체 만 반환합니다. 이것은 약간 까다 롭습니다.
그런 다음 생성기 for
사용할 때마다 중단 된 위치부터 코드가 계속됩니다.
이제 어려운 부분 :
for
가 함수에서 생성 된 생성기 객체를 처음 yield
에 도달 할 때까지 함수의 코드를 실행 한 다음 루프의 첫 번째 값을 반환합니다. 그런 다음 각 후속 호출은 함수에 작성한 루프의 또 다른 반복을 실행하고 다음 값을 반환합니다. 이는 생성기가 비어있는 것으로 간주 될 때까지 계속되며 이는 yield
도달하지 않고 함수가 실행될 때 발생합니다. 루프가 끝났거나 더 이상 "if/else"
충족하지 않기 때문일 수 있습니다.
코드 설명
발전기:
# Here you create the method of the node object that will return the generator def _get_child_candidates(self, distance, min_dist, max_dist): # Here is the code that will be called each time you use the generator object: # If there is still a child of the node object on its left # AND if the distance is ok, return the next child if self._leftchild and distance - max_dist < self._median: yield self._leftchild # If there is still a child of the node object on its right # AND if the distance is ok, return the next child if self._rightchild and distance + max_dist >= self._median: yield self._rightchild # If the function arrives here, the generator will be considered empty # there is no more than two values: the left and the right children
방문객:
# Create an empty list and a list with the current object reference result, candidates = list(), [self] # Loop on candidates (they contain only one element at the beginning) while candidates: # Get the last candidate and remove it from the list node = candidates.pop() # Get the distance between obj and the candidate distance = node._get_dist(obj) # If distance is ok, then you can fill the result if distance <= max_dist and distance >= min_dist: result.extend(node._values) # Add the children of the candidate in the candidate's list # so the loop will keep running until it will have looked # at all the children of the children of the children, etc. of the candidate candidates.extend(node._get_child_candidates(distance, min_dist, max_dist)) return result
이 코드에는 여러 스마트 부분이 포함되어 있습니다.
- 루프는 목록에서 반복되지만 루프가 반복되는 동안 목록이 확장됩니다. 무한 루프로 끝날 수 있기 때문에 약간 위험하더라도 이러한 모든 중첩 데이터를 통과하는 간결한 방법입니다. 이 경우,
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
배기 모든 발전기의 값이지만while
가 동일한 적용하지 이후 이전의 것과 다른 값을 생성하는 새로운 발전기 객체를 생성 유지 마디. extend()
메서드는 이터 러블을 예상하고 그 값을 목록에 추가하는 목록 객체 메서드입니다.
일반적으로 목록을 전달합니다.
>>> a = [1, 2] >>> b = [3, 4] >>> a.extend(b) >>> print(a) [1, 2, 3, 4]
그러나 코드에서 생성기를 가져옵니다.
- 값을 두 번 읽을 필요가 없습니다.
- 자녀가 많을 수 있으며 모두 메모리에 저장되는 것을 원하지 않습니다.
그리고 파이썬은 메소드의 인수가 목록인지 아닌지 상관하지 않기 때문에 작동합니다. 파이썬은 이터 러블을 기대하므로 문자열, 목록, 튜플 및 생성기와 함께 작동합니다! 이것은 오리 타이핑이라고 불리며 파이썬이 멋진 이유 중 하나입니다. 그러나 이것은 또 다른 이야기입니다. 다른 질문에 대해서는 ... 여기에서 멈추거나 발전기의 고급 사용법을보기 위해 조금 읽을 수 있습니다.
발전기 고갈 제어
>>> class Bank(): # Let's create a bank, building ATMs ... crisis = False ... def create_atm(self): ... while not self.crisis: ... yield "$100" >>> hsbc = Bank() # When everything's ok the ATM gives you as much as you want >>> corner_street_atm = hsbc.create_atm() >>> print(corner_street_atm.next()) $100 >>> print(corner_street_atm.next()) $100 >>> print([corner_street_atm.next() for cash in range(5)]) ['$100', '$100', '$100', '$100', '$100'] >>> hsbc.crisis = True # Crisis is coming, no more money! >>> print(corner_street_atm.next()) <type 'exceptions.StopIteration'> >>> wall_street_atm = hsbc.create_atm() # It's even true for new ATMs >>> print(wall_street_atm.next()) <type 'exceptions.StopIteration'> >>> hsbc.crisis = False # The trouble is, even post-crisis the ATM remains empty >>> print(corner_street_atm.next()) <type 'exceptions.StopIteration'> >>> brand_new_atm = hsbc.create_atm() # Build a new one to get back in business >>> for cash in brand_new_atm: ... print cash $100 $100 $100 $100 $100 $100 $100 $100 $100 ...
참고 : Python 3의 경우 print(corner_street_atm.__next__())
또는 print(next(corner_street_atm))
사용하세요. 리소스에 대한 액세스 제어와 같은 다양한 작업에 유용 할 수 있습니다.
Itertools, 당신의 가장 친한 친구
itertools 모듈에는 이터 러블을 조작하는 특수 함수가 포함되어 있습니다. 생성기를 복제하고 싶습니까? 두 개의 발전기를 연결 하시겠습니까? 한 줄로 중첩 된 목록의 값을 그룹화 하시겠습니까? 다른 목록을 만들지 않고 Map / Zip
그런 다음 import itertools
. 예? 네 경마의 가능한 도착 순서를 살펴 보겠습니다.
>>> horses = [1, 2, 3, 4] >>> races = itertools.permutations(horses) >>> print(races) <itertools.permutations object at 0xb754f1dc> >>> print(list(itertools.permutations(horses))) [(1, 2, 3, 4), (1, 2, 4, 3), (1, 3, 2, 4), (1, 3, 4, 2), (1, 4, 2, 3), (1, 4, 3, 2), (2, 1, 3, 4), (2, 1, 4, 3), (2, 3, 1, 4), (2, 3, 4, 1), (2, 4, 1, 3), (2, 4, 3, 1), (3, 1, 2, 4), (3, 1, 4, 2), (3, 2, 1, 4), (3, 2, 4, 1), (3, 4, 1, 2), (3, 4, 2, 1), (4, 1, 2, 3), (4, 1, 3, 2), (4, 2, 1, 3), (4, 2, 3, 1), (4, 3, 1, 2), (4, 3, 2, 1)]
반복의 내부 메커니즘 이해
반복은 반복자 ( __iter__()
메서드 구현)와 반복기 ( __next__()
메서드 구현)를 암시하는 프로세스입니다. 이터 러블은 이터레이터를 가져올 수있는 모든 객체입니다. 반복자는 반복 가능한 항목을 반복 할 수있는 객체입니다. 이 기사에는 for
루프가 작동하는 방법에 대한 자세한 내용이 있습니다.
Generator:
# Here you create the method of the node object that will return the generator
def _get_child_candidates(self, distance, min_dist, max_dist):
# Here is the code that will be called each time you use the generator object:
# If there is still a child of the node object on its left
# AND if the distance is ok, return the next child
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
# If there is still a child of the node object on its right
# AND if the distance is ok, return the next child
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
# If the function arrives here, the generator will be considered empty
# there is no more than two values: the left and the right children
Caller:
Create an empty list and a list with the current object reference
result, candidates = list(), [self]
# Loop on candidates (they contain only one element at the beginning)
while candidates:
# Get the last candidate and remove it from the list
node = candidates.pop()
# Get the distance between obj and the candidate
distance = node._get_dist(obj)
# If distance is ok, then you can fill the result
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
# Add the children of the candidate in the candidate's list
# so the loop will keep running until it will have looked
# at all the children of the children of the children, etc. of the candidate
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result
이 코드에는 여러 스마트 부분이 포함되어 있습니다.
- 루프는 목록에서 반복되지만 루프가 반복되는 동안 목록이 확장됩니다. 무한 루프로 끝날 수 있기 때문에 약간 위험하더라도 이러한 모든 중첩 데이터를 통과하는 간결한 방법입니다. 이 경우,
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
배기 모든 발전기의 값이지만while
가 동일한 적용하지 이후 이전의 것과 다른 값을 생성하는 새로운 발전기 객체를 생성 유지 마디. extend()
메서드는 이터 러블을 예상하고 그 값을 목록에 추가하는 목록 객체 메서드입니다.
일반적으로 목록을 전달합니다.
>>> a = [1, 2]
>>> b = [3, 4]
>>> a.extend(b)
>>> print(a)
[1, 2, 3, 4]
그러나 코드에서 생성기를 가져옵니다.
그리고 파이썬은 메소드의 인수가 목록인지 아닌지 상관하지 않기 때문에 작동합니다. 파이썬은 이터 러블을 기대하므로 문자열, 목록, 튜플 및 생성기와 함께 작동합니다! 이것은 오리 타이핑이라고 불리며 파이썬이 멋진 이유 중 하나입니다. 그러나 이것은 또 다른 이야기입니다.
여기에서 멈추거나 발전기의 고급 사용법을 확인하기 위해 조금 읽을 수 있습니다.
>>> class Bank(): # Let's create a bank, building ATMs
... crisis = False
... def create_atm(self):
... while not self.crisis:
... yield "$100"
>>> hsbc = Bank() # When everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
$100
>>> print(corner_street_atm.next())
$100
>>> print([corner_street_atm.next() for cash in range(5)])
['$100', '$100', '$100', '$100', '$100']
>>> hsbc.crisis = True # Crisis is coming, no more money!
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.create_atm() # It's even true for new ATMs
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # The trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # Build a new one to get back in business
>>> for cash in brand_new_atm:
... print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100
...
참고 : Python 3의 경우 print(corner_street_atm.__next__())
또는 print(next(corner_street_atm))
리소스에 대한 액세스 제어와 같은 다양한 작업에 유용 할 수 있습니다.
itertools 모듈에는 이터 러블을 조작하는 특수 함수가 포함되어 있습니다. 생성기를 복제하고 싶습니까? 두 개의 발전기를 연결 하시겠습니까? 한 줄로 중첩 된 목록의 값을 그룹화 하시겠습니까? 다른 목록을 만들지 않고 Map / Zip
그런 다음 import itertools
.
예? 네 경마의 가능한 도착 순서를 살펴 보겠습니다.
>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]
반복은 반복자 ( __iter__()
메서드 구현)와 반복기 ( __next__()
메서드 구현)를 암시하는 프로세스입니다. 이터 러블은 이터레이터를 가져올 수있는 모든 객체입니다. 반복자는 반복 가능한 항목을 반복 할 수있는 객체입니다.
이 기사에는 for
루프가 작동하는 방법에 대한 자세한 내용이 있습니다.
출처 : https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do
'프로그래밍 언어 > C++' 카테고리의 다른 글
C ++ functor와 그 용도 (0) | 2021.07.13 |
---|---|
주어진 키가 C ++ std :: map에 있는지 확인하는 방법 (0) | 2021.07.12 |
C ++ 식별자에서 "_"을 사용하는 규칙 (0) | 2021.07.09 |
Visual Studio C / C ++ 콘솔 애플리케이션에서 콘솔 창이 닫히지 않도록 방지 (0) | 2021.07.09 |
C ++에서 가상 기본 클래스 란? (0) | 2021.07.07 |