You could use np.roll(), which does a cyclic permutation / cyclic shift, along the specified axis (or axes)
If the shift happens along just axis1, use:
new_img = np.roll (img, split, axis=1)
where split is the col value at which your image is to be split. The effect of this cyclic shift is exactly as though the image had been split at the specified point on the axis, and the two resulting image-parts have been swapped.
Since you require to shift along axis1, and simultaneously slice along axis0, it would be:
new_img = np.roll (img[low:high,...], split, axis=[0,1])
where low and high are appropriate slice boundaries along axis0.
If a shift can happen along both axes simultaneously (and there is on slicing), it would be:
new_img = np.roll (img, [split_0, split_1], axis=[0,1])
where split_0 is the split point along axis0 and split_1 is the split point along axis1
Note: Somewhat surprisingly, instead of returning a view, roll() returns a copy, which means it may not give much of a speed-advantage, compared to stacking / concatenating.