Performs a depth-first search of a graph-like structure.

    :param start: Node to start the search from
    :param expand: Function taking a node as an argument and returning iterable
                   of its child nodes

    :return: Iterable of nodes in the DFS order

    Example::

        for node in depth_first(graph, attr_func('adjacent')):
            visit(node)

def depth_first(start, descend):
    """Performs a depth-first search of a graph-like structure.

    :param start: Node to start the search from
    :param expand: Function taking a node as an argument and returning iterable
                   of its child nodes

    :return: Iterable of nodes in the DFS order

    Example::

        for node in depth_first(graph, attr_func('adjacent')):
            visit(node)
    """
    ensure_callable(descend)

    def generator():
        stack = [start]
        while stack:
            node = stack.pop()
            yield node
            stack.extend(descend(node))

    return generator()