Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Empty generator

Playing around with trees, I stumbled over this behaviour:

def descendants (self):
    return #or "pass" or "42"

obviously returns None.

On the other hand side:

def descendants (self):
    return
    yield 42

returns a generator which yields nothing (actually the behaviour I needed for leaf nodes).

Could somebody explain to me what is happening under the hood here?

Shouldn't the yield 42 be unreachable code? (I guess the decision whether a function is a generator or a "normal" function is made at compile time, based on whether it contains one or various yield statements, be they reachable or not. But this is just a shot in the dark.)


The context is the following: I have trees and each node is either a tree or a leaf. Now I want to generate all the descendants of a node:

class Leaf (Node):
    @property
    def descendants (self):
        return
        yield 42

class Tree (Node):
    @property
    def descendants (self):
        for child in self.children:
            yield child
            yield from child.descendants
like image 520
Hyperboreus Avatar asked Apr 10 '14 03:04

Hyperboreus


People also ask

How do I return an empty generator?

You can use return once in a generator; it stops iteration without yielding anything, and thus provides an explicit alternative to letting the function run out of scope. So use yield to turn the function into a generator, but precede it with return to terminate the generator before yielding anything.

What are the generators in Python?

Python Generators are the functions that return the traversal object and used to create iterators. It traverses the entire items at once. The generator can also be an expression in which syntax is similar to the list comprehension in Python.

How do Python generators work?

A Python generator is a function that produces a sequence of results. It works by maintaining its local state, so that the function can resume again exactly where it left off when called subsequent times. Thus, you can think of a generator as something like a powerful iterator.

How do you use yield?

yield in Python can be used like the return statement in a function. When done so, the function instead of returning the output, it returns a generator that can be iterated upon. You can then iterate through the generator to extract items. Iterating is done using a for loop or simply using the next() function.


1 Answers

As I understand it, the yield keyword inside a function is detected at compile-time. The result is that the function no longer behaves like a normal function. When a function with a yield keyword is called, the function IMMEDIATELY returns a lazy generator object which produces variables as needed according to the defined function. The code in your function is only run when the generator is iterated through.

It's more succinctly explained here.

So descendants is called, and since the yield keyword is present in the function, a generator object is immediately returned. Since descendants immediately returns, however, the generator yields no values-but it's definitely still a generator.

like image 135
jayelm Avatar answered Oct 12 '22 08:10

jayelm