You can take advantage of NumPy array arithmetic to handle N dimensions the same as you would 1 dimension. Moreover, computing the slices for N dimension can be handled with
calls to map(slice, start_indices, end_indices), and once these slices are generated, the actual copying becomes a one-liner: B[B_slices] = A[A_slices]:
import numpy as np
def copy_from(A, B, A_start, B_start, B_end):
"""
A_start is the index with respect to A of the upper left corner of the overlap
B_start is the index with respect to B of the upper left corner of the overlap
B_end is the index of with respect to B of the lower right corner of the overlap
"""
A_start, B_start, B_end = map(np.asarray, [A_start, B_start, B_end])
shape = B_end - B_start
B_slices = tuple(map(slice, B_start, B_end + 1))
A_slices = tuple(map(slice, A_start, A_start + shape + 1))
B[B_slices] = A[A_slices]
A = np.zeros((21,15))
B = np.ones((16,15))
A_start = [11, 5]
B_start = [6, 0]
B_end = [15, 9]
copy_from(A, B, A_start, B_start, B_end)
print(B)
yields
[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1.]]
AandBwhat are the givens? How is the region of overlap specified?