|
|||||||
Как работает 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)] Понимание внутреннего механизма итерации
|
|||||||
|
|||||||
|