| 
 |||||||
| 
    Как работает yield 
        
        
		  Время создания: 10.09.2017 19:30		  
		 
		
		 		
		
		 		 
		  Текстовые метки: knowledge		  
		 		
		
				  
		    Раздел: Python - Types data - generator		   
		
		
		 		 
		  Запись: xintrea/mytetra_db_mcold/master/base/1505061034gj18vaz17e/text.html на raw.githubusercontent.com		  
		 
		
				  
  | 
 |||||||
| 
    | 
 |||||||
| 
    Как работает yield http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained 
 На StackOverflow часто задают вопросы, подробно освещённые в документации. Ценность их в том, что на некоторые из них кто-нибудь даёт ответ, обладающий гораздо большей степенью ясности и наглядности, чем может себе позволить документация. Этот — один из них. Как используется ключевое слово yield в Python? Что оно делает? 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 = list(), [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 
 Итераторы 
 >>> 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
 Yield 
 >>> def createGenerator() : ... mylist = range(3) ... for i in mylist : ... yield i*i ...
>>> mygenerator = createGenerator() # создаём генератор >>> print(mygenerator) # mygenerator является объектом! <generator object createGenerator at 0xb7555c34> >>> for i in mygenerator: ... print(i) 0
1
4
 Объяснение кода из исходного вопроса 
 # Создаём метод узла, который будет возвращать генератор
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 = list(), [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 
 
 
 >>> a = [1, 2] >>> b = [3, 4] >>> a.extend(b) >>> print(a) [1, 2, 3, 4] 
 
 
 Контроль за исчерпанием генератора >>> class Bank(): # создаём банк, строящий торговые автоматы (ATM — Automatic Teller Machine) ... crisis = False ... def create_atm(self) : ... while not self.crisis : ... yield "$100" >>> hsbc = Bank() # когда всё хорошо, можно получить сколько угодно денег с торгового автомата >>> 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 # пришёл кризис, денег больше нет! >>> print(corner_street_atm.next()) <type 'exceptions.StopIteration'> >>> wall_street_atm = hsbc.create_atm() # что верно даже для новых автоматов >>> print(wall_street_atm.next()) <type 'exceptions.StopIteration'> >>> hsbc.crisis = False # проблема в том, что когда кризис прошёл, автоматы по-прежнему пустые... >>> print(corner_street_atm.next()) <type 'exceptions.StopIteration'> >>> brand_new_atm = hsbc.create_atm() # но если построить ещё один, будешь снова в деле! >>> for cash in brand_new_atm : ... print cash $100 $100 $100 $100 $100 $100 $100 $100 $100 ...
 Ваш лучший друг 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)] Понимание внутреннего механизма итерации 
  | 
 |||||||
      
   | 
 |||||||
   
   
  | 
 |||||||
   
  |