You can use scipy.ndimage.zoom with the order set to 0 to keep replicating your array
>>> arr
array([[4, 5],
[7, 9]])
>>> scipy.ndimage.zoom(arr, 2, order=0)
array([[4, 4, 5, 5],
[4, 4, 5, 5],
[7, 7, 9, 9],
[7, 7, 9, 9]])
zoom also works with greater values and/or can approximate to floats (zooming in or out) and in different scales by-axis (including higher dimensions)
>>> scipy.ndimage.zoom(arr, 5, order=0)
array([[4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
[4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
[4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
[4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
[4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
[7, 7, 7, 7, 7, 9, 9, 9, 9, 9],
[7, 7, 7, 7, 7, 9, 9, 9, 9, 9],
[7, 7, 7, 7, 7, 9, 9, 9, 9, 9],
[7, 7, 7, 7, 7, 9, 9, 9, 9, 9],
[7, 7, 7, 7, 7, 9, 9, 9, 9, 9]])
>>> scipy.ndimage.zoom(arr, 0.5, order=0)
array([[4]])
>>> scipy.ndimage.zoom(arr, (2,3), order=0)
array([[4, 4, 4, 5, 5, 5],
[4, 4, 4, 5, 5, 5],
[7, 7, 7, 9, 9, 9],
[7, 7, 7, 9, 9, 9]])
first[0,0} * np.ones((2,2))and concatenating the results.