How do I reshape a list into a n-dimensional list
Input: 
list = [1, 2, 3, 4, 5, 6, 7, 8]
shape = [2, 2, 2]
output = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
This recursive approach should work.
lst = [1, 2, 3, 4, 5, 6, 7, 8]
shape = [2, 2, 2]
from functools import reduce 
from operator import mul
def reshape(lst, shape):
    if len(shape) == 1:
        return lst
    n = reduce(mul, shape[1:])
    return [reshape(lst[i*n:(i+1)*n], shape[1:]) for i in range(len(lst)//n)]
reshape(lst, shape)
You probably want to wrap that with a check that your dimensions make sense... e.g.
assert reduce(mul, shape) == len(lst)
 
    
    oooold post.. but since i'm currently looking for a more elegant way than mine, i just tell you my approach
# first, i create some data
l = [ i for i in range(256) ]
# now I reshape in to slices of 4 items
x = [ l[x:x+4] for x in range(0, len(l), 4) ] 
 
    
    Here is an approach using the grouper once on each dimension except the first:
import functools as ft
# example
L = list(range(2*3*4))
S = 2,3,4
# if tuples are acceptable 
tuple(ft.reduce(lambda x, y: zip(*y*(x,)), (iter(L), *S[:0:-1])))
# (((0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)), ((12, 13, 14, 15), (16, 17, 18, 19), (20, 21, 22, 23)))
# if it must be lists
list(ft.reduce(lambda x, y: map(list, zip(*y*(x,))), (iter(L), *S[:0:-1])))
# [[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]
 
    
    The code below should do the trick.
The solution given below very general. The input list can be a nested list of lists of an any old/undesired shape; it need not be a list of integers.
Also, there are separate re-usable tools. For example the all_for_one function is very handy. 
EDIT:
I failed to note something important. If you put 1s inside of the shape parameter, then you can get superfluous list nestings (only one list inside of a list instead of five or six lists inside of a list)
For example, if shape is [1, 1, 2]
then the return value might be [[[0.1, 0.2]]] instead of [0.1, 0.2]
the length of shape is the number of valid subscripts in the output list.
For example, 
shape = [1, 2] # length 2
lyst = [[0.1, 0.2]]
print(lyst[0][0])  # valid.... no KeyError raised
If you want a true column or row vector, then len(shape) must be 1.
For example, shape = [49] will give you a row/column vector of length 49.
shape = [2] # length 2
output = [0.1, 0.2]
print(lyst[0])  
Here's the code:
from operator import mul
import itertools as itts
import copy
import functools
one_for_all =  lambda one: itts.repeat(one, 1)
def all_for_one(lyst):
   """
    EXAMPLE:
        INPUT:
            [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
        OUTPUT:
            iterator to [1, 2, 3, 4, 5, 6, 7, 8]
    IN GENERAL:
        Gets iterator to all nested elements
        of a list of lists of ... of lists of lists.
    """
    # make an iterator which **IMMEDIATELY**
    # raises a `StopIteration` exception
    its = itts.repeat("", 0)
    for sublyst in lyst:
        if hasattr(sublyst, "__iter__") and id(sublyst) != id(lyst):
            # Be careful ....
            #
            # "string"[0] == "s"[0] == "s"[0][0][0][0][0][0]...
            #
            # do not drill down while `sublyst` has an "__iter__" method
            # do not drill down while `sublyst` has a `__getitem__` method
            #
            it = all_for_one(sublyst)
        else:
            it = one_for_all(sublyst)
        # concatenate results to what we had previously
        its = itts.chain(its, it)
    return its
merged = list(all_for_one([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]))
print("merged == ", merged)
def reshape(xread_lyst, xshape):
    """
    similar to `numpy.reshape`
    EXAMPLE:         
        lyst  = [1, 2, 3, 4, 5, 6, 7, 8]
        shape = [2, 2, 2]        
        result = reshape(lyst)
        print(result)
         result ==
         [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
    For this function, input parameter `xshape` can be
    any iterable containing at least one element.
    `xshape` is not required to be a tuple, but it can be.
    The length of xshape should be equal to the number
    of desired list nestings
    If you want a list of integers: len(xshape) == 1
    If you want a list of lists:    len(xshape) == 2
    If you want a list of lists of lists: len(xshape) == 3
    If xshape = [1, 2],
    outermost list has 1 element
    that one element is a list of 2 elements.
    result == [[1, 2]]
    If xshape == [2]
    outermost list has 2 elements
    those 2 elements are non-lists:
    result: [1, 2] 
    If xshape = [2, 2],
    outermost list has 2 elements
    each element is a list of 2 elements.
    result == [[1, 2] [3, 4]]
    """
    # BEGIN SANITIZING INPUTS
    # unfortunately, iterators are not re-usable
    # Also, they don't have `len` methods
    iread_lyst = [x for x in ReshapeTools.unnest(xread_lyst)]
    ishape = [x for x in self.unnest(xshape)]
    number_of_elements = functools.reduce(mul, ishape, 1)
    if(number_of_elements != len(iread_lyst)):
        msg = [str(x) for x in [
            "\nAn array having dimensions ", ishape,
            "\nMust contain ", number_of_elements, " element(s).",
            "\nHowever, we were only given ", len(iread_lyst), " element(s)."
        ]]
        if len(iread_lyst) < 10:
             msg.append('\nList before reshape: ')
             msg.append(str([str(x)[:5] for x in iread_lyst]))
        raise TypeError(''.join(msg))
    ishape = iter(ishape)
    iread_lyst = iter(iread_lyst)
    # END SANITATIZATION OF INPUTS
    write_parent = list()
    parent_list_len = next(ishape)
    try:
        child_list_len = next(ishape)
        for _ in range(0, parent_list_len):
            write_child = []
            write_parent.append(write_child)
            i_reshape(write_child, iread_lyst, child_list_len, copy.copy(ishape))
    except StopIteration:
        for _ in range(0, parent_list_len):
            write_child = next(iread_lyst)
            write_parent.append(write_child)
    return write_parent
def ilyst_reshape(write_parent, iread_lyst, parent_list_len, ishape):
    """
    You really shouldn't call this function directly.
    Try calling `reshape` instead
    The `i` in the name of this function stands for "internal"
    """
    try:
        child_list_len = next(ishape)
        for _ in range(0, parent_list_len):
            write_child = []
            write_parent.append(write_child)
            ilyst_reshape(write_child, iread_lyst, child_list_len, copy.copy(ishape))
    except StopIteration:
        for _ in range(0, parent_list_len):
            write_child = next(iread_lyst)
            write_parent.append(write_child)
    return None
three_dee_mat = reshape(merged, [2, 2, 2])
print("three_dee_mat == ", three_dee_mat)
 
    
    Not particularly elegant:
from functools import reduce
from itertools import islice
l=[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4]
s=[2,3,4]
if s and reduce(lambda x,y:x*y, s) == len(l):
    # if number of elements matches product of dimensions, 
    # the first dimension is actually redundant
    s=[1:]
else:
    print("length of input list does not match shape")
    return
while s:
  size = s.pop()  # how many elements for this dimension
  #split the list based on the size of the dimension
  it=iter(l)
  l = list(iter(lambda:list(islice(it,size)),[]))
# [[[1, 2, 3, 4], [5, 6, 7, 8], [9, 0, 1, 2]], 
#  [[3, 4, 5, 6], [7, 8, 9, 0], [1, 2, 3, 4]]]
 
    
    Similar to the top upvoted answer but somebody may find it helpful
def reshape(lst, shape):
    if not shape:
        return lst
    n = shape[0]
    lst = [lst[i * n:(i + 1) * n]
            for i in range(ceil(len(lst) / n))]
    return reshape(lst, shape[1:])