chain has an alternative chain.from_iterable constructor, which
takes an iterable of iterables. I find this useful when I have a set of
objects that have an iterable field, and want to get the set of all
those items.

generator functions are a convenient syntax for creating generators
from what looks like a normal function.

Rather than creating a container to keep the result of your calculation
and returning that at the end, you can yield the individual values,
and it will resume execution the next time you ask the iterator for the
next value.

They are useful for calculations where the result is not simple, and
may even be recursive.

Sub-generators

If you have python of version 3.3 or higher available, then you can use
the yield from statement to delegate to sub-generators.

def foo(bar):
yield bar
for baz in bar.qux:
yield from foo(baz)

In this example, rather than using yield from, you can do:

for x in foo(baz):
yield x

However this is longer and doesn't handle the potential interesting
corner cases where values can be passed into a generator function or
returned when iteration ends.

Context managers

Context managers are used with the with statement. A context manager
can be any object that defines the __enter__ and __exit__ methods.

You don't need a dedicated object to be a context manager, using the
open file object as a context manager will have it close the file at
the end of the with block. It is common to use open this way:

with open('foo.txt', 'w') as f:
f.write('bar\n')

You can define the __enter__ and __exit__ methods yourself, but
provided you don't need much logic at construction time (you rarely
do) and you don't need it to be re-usable, you can define a context
manager like:

This uses a generator function that yields only one value (in this case we
yield a None implicitly), and mostly exists so that you can run cleanup
code after it has finished and re-enters your generator function.

The try...finally is necessary because when you yield in a context
manager, it is resumed when the with block finishes, which can be from
an exception. If it is from an exception then it is raised inside the
context manager function, so to ensure that the chdir is always run,
you need to wrap the yield in a try...finally block.