<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def normalized_index_expression(indices, shape, int_to_slice=False):
 """Enable indexing with almost Numpy-like capabilities. Implements the following features: - Usage of general slices and sequences of slices - Conversion of `Ellipsis` into an adequate number of ``slice(None)`` objects - Fewer indices than axes by filling up with an `Ellipsis` - Error checking with respect to a given shape - Conversion of integer indices into corresponding slices Parameters indices : int, `slice`, `Ellipsis` or sequence of these Index expression to be normalized. shape : sequence of ints Target shape for error checking of out-of-bounds indices. Also needed to determine the number of axes. int_to_slice : bool, optional If ``True``, turn integers into corresponding slice objects. Returns ------- normalized : tuple of ints or `slice`'s Normalized index expression Examples -------- Sequences are turned into tuples. We can have at most as many entries as the length of ``shape``, but fewer are allowed - the remaining list places are filled up by ``slice(None)``: (1, 2, 3) (1, 2, slice(None, None, None)) (slice(None, 2, None), 2, slice(None, None, None)) (1, slice(None, None, None), slice(None, None, None)) By default, integer indices are kept. If they should be converted to slices, use ``int_to_slice=True``. This can be useful to guarantee that the result of slicing with the returned object is of the same type as the array into which is sliced and has the same number of axes: (slice(1, 2, None), slice(2, 3, None), slice(3, 4, None)) array([[[ 0.]]]) (1, 2, 3) 0.0 """

    ndim = len(shape)
    # Support indexing with fewer indices as indexing along the first
    # corresponding axes. In the other cases, normalize the input.
    if np.isscalar(indices):
        indices = [indices, Ellipsis]
    elif (isinstance(indices, slice) or indices is Ellipsis):
        indices = [indices]

    indices = list(indices)
    if len(indices) < ndim and Ellipsis not in indices:
        indices.append(Ellipsis)

    # Turn Ellipsis into the correct number of slice(None)
    if Ellipsis in indices:
        if indices.count(Ellipsis) > 1:
            raise ValueError('cannot use more than one Ellipsis.')

        eidx = indices.index(Ellipsis)
        extra_dims = ndim - len(indices) + 1
        indices = (indices[:eidx] + [slice(None)] * extra_dims +
                   indices[eidx + 1:])

    # Turn single indices into length-1 slices if desired
    for (i, idx), n in zip(enumerate(indices), shape):
        if np.isscalar(idx):
            if idx < 0:
                idx += n

            if idx >= n:
                raise IndexError('Index {} is out of bounds for axis '
                                 '{} with size {}.'
                                 ''.format(idx, i, n))
            if int_to_slice:
                indices[i] = slice(idx, idx + 1)

    # Catch most common errors
    if any(s.start == s.stop and s.start is not None or
           s.start == n
           for s, n in zip(indices, shape) if isinstance(s, slice)):
        raise ValueError('Slices with empty axes not allowed.')
    if None in indices:
        raise ValueError('creating new axes is not supported.')
    if len(indices) > ndim:
        raise IndexError('too may indices: {} > {}.'
                         ''.format(len(indices), ndim))

    return tuple(indices)