iterator - python - ¿Qué hace la palabra clave "yield"?

python / generator / yield / coroutine

¿Cuál es el uso de la palabra clave yield en Python y qué hace?

Por ejemplo, estoy tratando de entender este código 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  

Y esta es la persona que llama:

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

iliketocode



Answer #1

En el estilo de paso de continuación (CPS),las continuaciones son simplemente funciones normales (sólo en los lenguajes donde las funciones son de primera clase)que el programador gestiona explícitamente y pasa a las subrutinas.En este estilo,el estado del programa está representado por cierres (y las variables que resultan estar codificadas en ellos)en lugar de variables que residen en algún lugar de la pila.Las funciones que gestionan el flujo de control aceptan continuaciones como argumentos (en algunas variaciones de CPS,las funciones pueden aceptar múltiples continuaciones)y manipulan el flujo de control invocándolas simplemente llamándolas y devolviendo después.Un ejemplo muy sencillo del estilo de pasar continuaciones es el siguiente:

def save_file(filename):
  def write_file_continuation():
    write_stuff_to_file(filename)

  check_if_file_exists_and_user_wants_to_overwrite(write_file_continuation)

Ahora hablemos de generadores en Python. Los generadores son un subtipo específico de continuación. Mientras que las continuaciones pueden, en general, guardar el estado de un cálculo (es decir, la pila de llamadas del programa), los generadores solo pueden guardar el estado de iteración en un iterador . Aunque, esta definición es un poco engañosa para ciertos casos de uso de generadores. Por ejemplo:

def f():
  while True:
    yield 4
class Generator():
  def __init__(self,iterable,generatorfun):
    self.next_continuation = lambda:generatorfun(iterable)

  def next(self):
    value, next_continuation = self.next_continuation()
    self.next_continuation = next_continuation
    return value
def generatorfun(iterable):
  if len(iterable) == 0:
    raise StopIteration
  else:
    return (iterable[0], lambda:generatorfun(iterable[1:]))