nodes: 0, module; 1, function_definition; 2, function_name:_generate_comparator; 3, parameters; 4, block; 5, identifier:cls; 6, identifier:field_names; 7, expression_statement; 8, comment:# Ensure that field names is a list and not a tuple.; 9, expression_statement; 10, comment:# For fields that start with a '-', reverse the ordering of the; 11, comment:# comparison.; 12, expression_statement; 13, for_statement; 14, expression_statement; 15, function_definition; 16, return_statement; 17, comment:"""
          Construct a comparator function based on the field names. The comparator
          returns the first non-zero comparison value.
  
          Inputs:
              field_names (iterable of strings): The field names to sort on.
  
          Returns:
              A comparator function.
          """; 18, assignment; 19, assignment; 20, pattern_list; 21, call; 22, block; 23, assignment; 24, function_name:comparator; 25, parameters; 26, comment:# Get a tuple of values for comparison.; 27, block; 28, identifier:comparator; 29, identifier:field_names; 30, call; 31, identifier:reverses; 32, binary_operator:[1] * len(field_names); 33, identifier:i; 34, identifier:field_name; 35, identifier:enumerate; 36, argument_list; 37, if_statement; 38, identifier:field_names; 39, list_comprehension; 40, identifier:i1; 41, identifier:i2; 42, expression_statement; 43, expression_statement; 44, comment:# If there's only one arg supplied, attrgetter returns a single; 45, comment:# item, directly return the result in this case.; 46, if_statement; 47, comment:# Compare each field for the two items, reversing if necessary.; 48, expression_statement; 49, try_statement; 50, identifier:list; 51, argument_list; 52, list; 53, call; 54, identifier:field_names; 55, comparison_operator:field_name[0] == '-'; 56, block; 57, call; 58, for_in_clause; 59, assignment; 60, assignment; 61, comparison_operator:len(field_names) == 1; 62, block; 63, assignment; 64, comment:# The first non-zero element.; 65, block; 66, except_clause; 67, identifier:field_names; 68, integer:1; 69, identifier:len; 70, argument_list; 71, subscript; 72, string; 73, expression_statement; 74, expression_statement; 75, attribute; 76, argument_list; 77, identifier:f; 78, identifier:field_names; 79, identifier:v1; 80, call; 81, identifier:v2; 82, call; 83, call; 84, integer:1; 85, return_statement; 86, identifier:order; 87, call; 88, return_statement; 89, identifier:StopIteration; 90, comment:# Everything was equivalent.; 91, block; 92, identifier:field_names; 93, identifier:field_name; 94, integer:0; 95, string_content:-; 96, assignment; 97, assignment; 98, identifier:f; 99, identifier:replace; 100, identifier:LOOKUP_SEP; 101, string; 102, call; 103, argument_list; 104, call; 105, argument_list; 106, identifier:len; 107, argument_list; 108, binary_operator:cls._cmp(v1, v2) * reverses[0]; 109, identifier:multiply_iterables; 110, argument_list; 111, call; 112, return_statement; 113, subscript; 114, unary_operator; 115, subscript; 116, subscript; 117, string_content:.; 118, identifier:attrgetter; 119, argument_list; 120, identifier:i1; 121, identifier:attrgetter; 122, argument_list; 123, identifier:i2; 124, identifier:field_names; 125, call; 126, subscript; 127, call; 128, identifier:reverses; 129, identifier:next; 130, argument_list; 131, integer:0; 132, identifier:reverses; 133, identifier:i; 134, integer:1; 135, identifier:field_names; 136, identifier:i; 137, identifier:field_name; 138, slice; 139, list_splat; 140, list_splat; 141, attribute; 142, argument_list; 143, identifier:reverses; 144, integer:0; 145, identifier:list; 146, argument_list; 147, call; 148, integer:1; 149, identifier:field_names; 150, identifier:field_names; 151, identifier:cls; 152, identifier:_cmp; 153, identifier:v1; 154, identifier:v2; 155, call; 156, identifier:dropwhile; 157, argument_list; 158, identifier:map; 159, argument_list; 160, identifier:__not__; 161, identifier:order; 162, attribute; 163, identifier:v1; 164, identifier:v2; 165, identifier:cls; 166, identifier:_cmp
code: def _generate_comparator(cls, field_names):
          """
          Construct a comparator function based on the field names. The comparator
          returns the first non-zero comparison value.
  
          Inputs:
              field_names (iterable of strings): The field names to sort on.
  
          Returns:
              A comparator function.
          """
          # Ensure that field names is a list and not a tuple.
          field_names = list(field_names)
  
          # For fields that start with a '-', reverse the ordering of the
          # comparison.
          reverses = [1] * len(field_names)
          for i, field_name in enumerate(field_names):
              if field_name[0] == '-':
                  reverses[i] = -1
                  field_names[i] = field_name[1:]
  
          field_names = [f.replace(LOOKUP_SEP, '.') for f in field_names]
  
          def comparator(i1, i2):
              # Get a tuple of values for comparison.
              v1 = attrgetter(*field_names)(i1)
              v2 = attrgetter(*field_names)(i2)
  
              # If there's only one arg supplied, attrgetter returns a single
              # item, directly return the result in this case.
              if len(field_names) == 1:
                  return cls._cmp(v1, v2) * reverses[0]
  
              # Compare each field for the two items, reversing if necessary.
              order = multiply_iterables(list(map(cls._cmp, v1, v2)), reverses)
  
              try:
                  # The first non-zero element.
                  return next(dropwhile(__not__, order))
              except StopIteration:
                  # Everything was equivalent.
                  return 0
  
          return comparator