code: def eval_set(self, evals, iteration=0, feval=None):
          # pylint: disable=invalid-name
          
          if feval is None:
              for d in evals:
                  if not isinstance(d[0], DMatrix):
                      raise TypeError('expected DMatrix, got {}'.format(type(d[0]).__name__))
                  if not isinstance(d[1], STRING_TYPES):
                      raise TypeError('expected string, got {}'.format(type(d[1]).__name__))
                  self._validate_features(d[0])
  
              dmats = c_array(ctypes.c_void_p, [d[0].handle for d in evals])
              evnames = c_array(ctypes.c_char_p, [c_str(d[1]) for d in evals])
              msg = ctypes.c_char_p()
              _check_call(_LIB.XGBoosterEvalOneIter(self.handle, iteration,
                                                    dmats, evnames, len(evals),
                                                    ctypes.byref(msg)))
              return msg.value
          else:
              res = '[%d]' % iteration
              for dmat, evname in evals:
                  name, val = feval(self.predict(dmat), dmat)
                  res += '\t%s-%s:%f' % (evname, name, val)
              return res
docs: Evaluate  a set of data.
  
          Parameters
          ----------
          evals : list of tuples (DMatrix, string)
              List of items to be evaluated.
          iteration : int
              Current iteration.
          feval : function
              Custom evaluation function.
  
          Returns
          -------
          result: str
              Evaluation result string.