Moving window with complete boundary in Python
numpy has a pad function.  It has many options, but this extends your array from a (10,10) to (12,12), which can be partitioned a 3x3 set of (4,4) windows.

np.pad(A,((0,2),(0,2)),mode='constant',constant_values=0)

array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  0],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  0,  0],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29,  0,  0],
       [30, 31, 32, 33, 34, 35, 36, 37, 38, 39,  0,  0],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49,  0,  0],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59,  0,  0],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69,  0,  0],
       [70, 71, 72, 73, 74, 75, 76, 77, 78, 79,  0,  0],
       [80, 81, 82, 83, 84, 85, 86, 87, 88, 89,  0,  0],
       [90, 91, 92, 93, 94, 95, 96, 97, 98, 99,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0]])


Your 'extend' returns a (20,20) array.  extend_image(A,steps=12).astype(int)[:12,:12] produces the same (12,12).  It is faster than np.pad (by about 30%).

numpy/lib/arraypad.py contains pad and the functions it uses, it you want to learn from it.  Looks like it uses np.concatenate.

In this case of just padding with 0s, here's an even faster (but not as general) a solution:

def foo(A,step=2):
    shape=(A.shape[0]+step,A.shape[1]+step)
    A1=np.zeros(shape, A.dtype)
    A1[:A.shape[0], :A.shape[1]] = A
    return A1