'Initializes a DataHandler.
Args:
op: Operation protocol buffer.
data_name_list: List of data names that should be put together. (Usually
refers to a list of different modalities, e.g., [\'data\', \'label\'] or
[\'image\', \'audio\'].)
hyperparameter_list: List of hyperparameters, one for each modality.
frac: What fraction of the total memory should this data handler use.'

def __init__(self, op, data_name_list, hyperparameter_list, frac=1.0):

    filenames = []
    numdim_list = []
    datasetsize = None
    left_window = []
    right_window = []
    stats_files = []
    shift = []
    add_noise = []
    shift_amt_x = []
    shift_amt_y = []
    keys = []
    typesize = 4
    if isinstance(op, str):
        op = util.ReadOperation(op)
    self.verbose = op.verbose
    verbose = self.verbose
    data_proto_file = os.path.join(op.data_proto_prefix, op.data_proto)
    dataset_proto = util.ReadData(data_proto_file)
    seq = False
    is_train = False
    for (name, hyp) in zip(data_name_list, hyperparameter_list):
        data_proto = next((d for d in dataset_proto.data if (d.name == name)))
        file_pattern = os.path.join(dataset_proto.prefix, data_proto.file_pattern)
        filenames.append(sorted(glob.glob(file_pattern)))
        stats_files.append(os.path.join(dataset_proto.prefix, data_proto.stats_file))
        numdims = np.prod(np.array(data_proto.dimensions))
        if (not data_proto.sparse):
            numdims *= data_proto.num_labels
        numdim_list.append(numdims)
        seq = (seq or data_proto.seq)
        left_window.append(hyp.left_window)
        right_window.append(hyp.right_window)
        add_noise.append(hyp.add_noise)
        shift.append(hyp.shift)
        shift_amt_x.append(hyp.shift_amt_x)
        shift_amt_y.append(hyp.shift_amt_y)
        keys.append(data_proto.key)
        is_train = ('train' in name)
        if (datasetsize is None):
            datasetsize = data_proto.size
        else:
            assert (datasetsize == data_proto.size), ('Size    of    %s    is    not    %d' % (name, datasetsize))
    if seq:
        max_rw = max(right_window)
        max_lw = max(left_window)
        actual_datasetsize = datasetsize
        datasetsize += (len(filenames[0]) * (max_rw + max_lw))
    numdims = sum(numdim_list)
    batchsize = op.batchsize
    randomize = op.randomize
    self.get_last_piece = op.get_last_piece
    total_disk_space = ((datasetsize * numdims) * typesize)
    max_gpu_capacity = int((frac * GetBytes(dataset_proto.gpu_memory)))
    max_cpu_capacity = int((frac * GetBytes(dataset_proto.main_memory)))
    vectorsize_bytes = (typesize * numdims)
    batchsize_bytes = (vectorsize_bytes * batchsize)
    max_gpu_capacity = ((max_gpu_capacity / batchsize_bytes) * batchsize_bytes)
    gpu_capacity = min(total_disk_space, max_gpu_capacity)
    cpu_capacity = min(total_disk_space, max_cpu_capacity)
    num_gpu_batches = (gpu_capacity / batchsize_bytes)
    num_cpu_batches = (cpu_capacity / batchsize_bytes)
    gpu_left_overs = ((gpu_capacity / vectorsize_bytes) - (num_gpu_batches * batchsize))
    cpu_left_overs = ((cpu_capacity / vectorsize_bytes) - (num_cpu_batches * batchsize))
    if self.verbose:
        if seq:
            num_valid_gpu_vectors = ((gpu_capacity / vectorsize_bytes) - (len(filenames[0]) * (max_rw + max_lw)))
            print num_valid_gpu_vectors
        else:
            print ('Batches    in    GPU    memory:    %d    +    leftovers    %d' % (num_gpu_batches, gpu_left_overs))
            print ('Batches    in    main    memory:    %d    +    leftovers    %d' % (num_cpu_batches, cpu_left_overs))
            print ('Batches    in    disk:    %d    +    leftovers    %d' % ((datasetsize / batchsize), (datasetsize % batchsize)))
    if seq:
        import sequence_datahandler as seq_dh
        self.disk = seq_dh.SequenceDisk(filenames, numdim_list, datasetsize, keys=keys, left_window=left_window, right_window=right_window, verbose=verbose)
        self.cpu_cache = seq_dh.SequenceCache(self.disk, cpu_capacity, numdim_list, typesize=typesize, randomize=randomize, left_window=left_window, right_window=right_window, verbose=verbose)
        self.gpu_cache = seq_dh.SequenceGPUCache(self.cpu_cache, gpu_capacity, numdim_list, typesize=typesize, randomize=randomize, left_window=left_window, right_window=right_window, verbose=verbose, batchsize=batchsize)
    else:
        self.disk = Disk(filenames, numdim_list, datasetsize, keys=keys, verbose=self.verbose)
        self.cpu_cache = Cache(self.disk, cpu_capacity, numdim_list, typesize=typesize, randomize=randomize, verbose=self.verbose)
        self.gpu_cache = GPUCache(self.cpu_cache, gpu_capacity, numdim_list, typesize=typesize, randomize=randomize, verbose=self.verbose, shift=shift, add_noise=add_noise, center_only=(not is_train), shift_amt_x=shift_amt_x, shift_amt_y=shift_amt_y)
    for (i, stats_file) in enumerate(stats_files):
        if (hyperparameter_list[i].normalize and (hyperparameter_list[i].activation != deepnet_pb2.Hyperparams.REPLICATED_SOFTMAX)):
            self.gpu_cache.SetDataStats(i, stats_file)
    self.batchsize = batchsize
    if seq:
        datasetsize = actual_datasetsize
    self.num_batches = (datasetsize / batchsize)
    if (self.get_last_piece and ((datasetsize % batchsize) > 0)):
        self.num_batches += 1
