What does the "yield" keyword do? 해결법
수율이 무엇을 하는지 이해하려면 제너레이터가 무엇인지 이해해야 합니다. 그리고 발전기를 이해하기 전에, 여러분은 반드시 반복해서 사용할 수 있는 것들을 이해해야 합니다.
읽을거리
목록을 만들 때 목록의 항목을 하나씩 읽을 수 있습니다. 항목을 하나씩 읽는 것을 반복이라고 합니다:
>>> mylist = [1, 2, 3] >>> for i in mylist: ... print(i) 1 2 3
내 리스트는 참을 수 있다. 목록 이해를 사용할 때 목록을 작성하므로 필수:
>>> mylist = [x*x for x in range(3)] >>> for i in mylist: ... print(i) 0 1 4
""를 사용할 수 있는 모든 것은...
"은(는) 반복할 수 있는 항목입니다. 목록
, , 파일...
이 반복 가능한 책들은 원하는 만큼 읽을 수 있기 때문에 편리하지만, 모든 값을 메모리에 저장하고, 값이 많을 때는 항상 이것이 당신이 원하는 것이 아니다.
발전기
발전기는 반복기이며, 한 번만 반복할 수 있는 일종의 반복기입니다. 생성기가 모든 값을 메모리에 저장하는 것은 아니며, 값을 즉시 생성합니다. :
>>> mygenerator = (x*x for x in range(3)) >>> for i in mygenerator: ... print(i) 0 1 4
당신이 []
대신 ()
를 사용한 것을 제외하고는 똑같다. 그러나 생성기는 한 번만 사용할 수 있기 때문에 생성기에서 i에 대해 두 번째로 수행할 수 없습니다. 0을 계산한 다음 잊어버리고 1을 계산하고 4를 하나씩 계산합니다.
Yield
수율은 함수가 제너레이터를 반환한다는 점을 제외하고는
리턴처럼 사용되는 키워드입니다.
>>> 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
여기서 이것은 쓸모없는 예이지만, 당신의 기능이 당신이 한 번만 읽으면 되는 엄청난 값들을 반환할 것이라는 것을 알고 있을 때 유용하다.
수율
를 마스터하려면 함수를 호출할 때 함수 본문에 작성한 코드가 실행되지 않음을 이해해야 합니다. 이 함수는 제너레이터 개체만 반환합니다. 이것은 좀 까다롭습니다.
그러면 생성기를 사용할 때마다 코드가 중단된 위치에서 코드가 계속됩니다.
이제 어려운 부분:
함수에서 생성된 생성기 개체를 처음 호출할 때, 처음부터 코드가 "code" 수율에 도달할 때까지 함수에서 코드를 실행한 다음 루프의 첫 번째 값을 반환합니다. 그런 다음 각 후속 호출은 함수에 작성한 루프의 다른 반복을 실행하고 다음 값을 반환합니다. 이는 제너레이터가 비어 있는 것으로 간주될 때까지 계속되며, 이는 함수가 수율을 치지 않고 실행될 때 발생합니다. 루프가 종료되었거나 더 이상
"if/else"를 만족하지 못하기 때문일 수 있습니다.
당신의 코드가 설명되었습니다.
�em� 생성자: �/em��/p�
# 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 are no more than two values: the left and the right children
<< />aller:>
# 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 the distance is ok, then you can fill in the result if distance <= max_dist and distance >= min_dist: result.extend(node._values) # Add the children of the candidate to the candidate's list # so the loop will keep running until it has 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
이 코드에는 여러 스마트 부품이 포함되어 있습니다.
- 루프가 목록에서 반복되지만 루프가 반복되는 동안 목록이 확장됩니다. 무한 루프로 끝날 수 있기 때문에 조금 위험하더라도 이 모든 중첩된 데이터를 처리하는 간결한 방법입니다. 이 경우 <코드> 후보입니다.확장(노드)._get_child_distates(distance, min_dist, max_dist)는 생성기의 모든 값을 소진하지만, 동일한 노드에 적용되지 않기 때문에 이전과 다른 값을 생성하는 새 생성기 개체를 계속 생성합니다.</코드>
확장()
메서드는 목록 개체 메서드로, 이 메서드를 기대하고 해당 값을 목록에 추가합니다.
일반적으로 목록을 전달합니다.
>>> a = [1, 2] >>> b = [3, 4] >>> a.extend(b) >>> print(a) [1, 2, 3, 4]
하지만 당신의 코드에서는 발전기가 나오는데, 이것은 다음과 같은 이유로 좋다:
- 값을 두 번 읽을 필요는 없습니다.
- 여러분은 아이들이 많을 수도 있고 그들 모두가 기억에 저장되는 것을 원하지 않을 수도 있습니다.
그리고 Python은 메소드의 인수가 목록인지 아닌지를 신경 쓰지 않기 때문에 작동한다. 파이썬은 반복 가능한 것을 기대하기 때문에 문자열, 목록, 튜플 및 생성기와 함께 작동할 것입니다! 이것은 오리 타이핑이라고 불리며 파이썬이 멋진 이유 중 하나이다. 하지만 이건 또 다른 이야기야, 또 다른 질문을 하자면...
발전기의 고급 사용법을 보려면 여기서 멈추거나 조금 읽을 수 있습니다.
발전기 배기량 제어
>>> 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__()
또는 프린트(next(next_street_filename))
</강함>
리소스에 대한 액세스 제어와 같은 다양한 작업에 유용할 수 있습니다.
Itter tools, 너의 가장 친한 친구
반복 도구 모듈에는 반복 가능한 항목을 조작하는 특수 기능이 포함되어 있습니다. 발전기를 복제해 본 적이 있습니까? 발전기 2개를 연결해? 중첩된 목록의 값을 단일 라이너로 그룹화하시겠습니까? 다른 목록을 만들지 않고 지도/Zip
를 선택하시겠습니까?
그런 다음 가져오기 도구를 사용하십시오.
예를 들면요? 네 마리 경주의 도착 순서를 보자:
>>> 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_() 메서드 구현)를 암시하는 프로세스이다. 반복 도구는 반복 도구를 얻을 수 있는 모든 개체입니다. 반복기는 반복 가능한 항목에서 반복할 수 있는 개체입니다.