How to split a numpy array in fixed size chunks with and without overlap?

There's a builtin in scikit-image as view_as_windows for doing exactly that -

from skimage.util.shape import view_as_windows

view_as_windows(arr, (2,2))

Sample run -

In [40]: arr
Out[40]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [41]: view_as_windows(arr, (2,2))
Out[41]: 
array([[[[0, 1],
         [3, 4]],

        [[1, 2],
         [4, 5]]],


       [[[3, 4],
         [6, 7]],

        [[4, 5],
         [7, 8]]]])

For the second part, use its cousin from the same family/module view_as_blocks -

from skimage.util.shape import view_as_blocks

view_as_blocks(arr, (2,2))