'Retrieve ``data`` associated with ``key``.
This algorithm looks into ``self._substitutions_dict`` for all
``TensorHead`` in the ``TensExpr`` (or just ``TensorHead`` if key is a
TensorHead instance). It reconstructs the components data that the
tensor expression should have by performing on components data the
operations that correspond to the abstract tensor operations applied.
Metric tensor is handled in a different manner: it is pre-computed in
``self._substitutions_dict_tensmul``.'

def _get(self, key):

    if (key in self._substitutions_dict):
        return self._substitutions_dict[key]
    if isinstance(key, TensorHead):
        return None
    if isinstance(key, Tensor):
        signature = tuple([i.is_up for i in key.get_indices()])
        srch = ((key.component,) + signature)
        if (srch in self._substitutions_dict_tensmul):
            return self._substitutions_dict_tensmul[srch]
        array_list = [self.data_from_tensor(key)]
        return self.data_contract_dum(array_list, key.dum, key.ext_rank)
    if isinstance(key, TensMul):
        tensmul_args = key.args
        if ((len(tensmul_args) == 1) and (len(tensmul_args[0].components) == 1)):
            signature = tuple([i.is_up for i in tensmul_args[0].get_indices()])
            srch = ((tensmul_args[0].components[0],) + signature)
            if (srch in self._substitutions_dict_tensmul):
                return self._substitutions_dict_tensmul[srch]
        data_list = [self.data_from_tensor(i) for i in tensmul_args if isinstance(i, TensExpr)]
        coeff = prod([i for i in tensmul_args if (not isinstance(i, TensExpr))])
        if all([(i is None) for i in data_list]):
            return None
        if any([(i is None) for i in data_list]):
            raise ValueError('Mixing    tensors    with    associated    components    data    with    tensors    without    components    data')
        data_result = self.data_contract_dum(data_list, key.dum, key.ext_rank)
        return (coeff * data_result)
    if isinstance(key, TensAdd):
        data_list = []
        free_args_list = []
        for arg in key.args:
            if isinstance(arg, TensExpr):
                data_list.append(arg.data)
                free_args_list.append([x[0] for x in arg.free])
            else:
                data_list.append(arg)
                free_args_list.append([])
        if all([(i is None) for i in data_list]):
            return None
        if any([(i is None) for i in data_list]):
            raise ValueError('Mixing    tensors    with    associated    components    data    with    tensors    without    components    data')
        sum_list = []
        from .array import permutedims
        for (data, free_args) in zip(data_list, free_args_list):
            if (len(free_args) < 2):
                sum_list.append(data)
            else:
                free_args_pos = {y: x for (x, y) in enumerate(free_args)}
                axes = [free_args_pos[arg] for arg in key.free_args]
                sum_list.append(permutedims(data, axes))
        return reduce((lambda x, y: (x + y)), sum_list)
    return None
