def pretty_print_differences(expected_xml_leftovers, live_xml_leftovers, verbose=False, sort_result=True):
    """
    Pretty prints differences output by diff_xml().

    Takes diff lists output by diff_xml() and generates a list of strings
    for logging purposes. Strings are sorted such that related mismatches are
    usually printed next to each other, and lined up with each other in order
    to make the differences easier for a human to spot.

    :param expected_xml_leftovers: The list of remaining element representations
        in the expected XML that were left after comparing to the live XML.
    :type expected_xml_leftovers: list
    :param live_xml_leftovers: The list of remaining element representations
        in the live XML that were left after comparing to the expected XML.
    :type live_xml_leftovers: list
    :param verbose: If True, element attributes for ancestor elements are also
        printed. If False, only tags are returned for ancestors.
    :type verbose: bool
    :returns: List of strings, each representing one of the input mismatches.
    :rtype: list
    """
    # Define the transform function once at the top, so we don't have to check
    # verbose each time we go to build a string. Speed, speed, speed.
    if verbose is True:
        elem_tuple_to_str = lambda x: ''.join([x[0], str(x[1])])
    else:
        elem_tuple_to_str = lambda x: x[0]

    # Setting this up lets us de-dupe the loop below.
    work_dict = {'Expected: /': expected_xml_leftovers,
                 'Live    : /': live_xml_leftovers}

    # Turning the below into a list comprehension is faster... by about 2%.l
    # But it's 200% harder to understand.
    combined_leftovers = []
    for prefix, leftover_list in work_dict.items():
        for leftover in leftover_list:
            # We keep the string in a few different pieces to allow us to
            # sort/group similar elements together, i.e. put expected values
            # next to their likely live counterparts.
            if leftover[-1][2] is None:  # Another check for None. We don't just str() it, cause we don't want
                elem_text = ''           # the printed string to look like '[None]'.
            else:
                elem_text = leftover[-1][2]

            string_parts = [prefix,
                            '/'.join([elem_tuple_to_str(e) for e in leftover]),
                            ''.join(['[', elem_text, ']'])]
            combined_leftovers.append(string_parts)

    # Sort the parts, then join them into their final strings. Sort first
    # by ancestry, then put Expected above Live for each ancestry group.
    if sort_result is True:
        result_strings = [''.join(leftover) for leftover in
                          sorted(combined_leftovers, key=lambda x: (x[1], x[0]))]
    else:
        result_strings = [''.join(leftover) for leftover in sorted(combined_leftovers, key=lambda x: x[0])]
    return result_strings