In [118]: np.subtract.outer(x,y)
Out[118]:
array([[-2, -3, -4, -5],
[-1, -2, -3, -4],
[ 0, -1, -2, -3],
[ 1, 0, -1, -2]])
The outer action can be duplicated with broadcasting:
In [120]: np.subtract(x[:,None],y) # x[:,None]-y
Out[120]:
array([[-2, -3, -4, -5],
[-1, -2, -3, -4],
[ 0, -1, -2, -3],
[ 1, 0, -1, -2]])
That can be generalized to more dimensions. just so long as you obey the broadcasting rules.
Because of the power of broadcasting, I haven't tried to work out what the ufunc.outer does in multidimensional array. With a pair of 1d arrays the action is obvious, and simply illustrated in the docs.
Here's a good illustration of how outer combines axes:
In [132]: np.subtract.outer(np.ones((2,3)), np.ones((4,5))).shape
Out[132]: (2, 3, 4, 5)
it doesn't accept an axis parameter, so there's no way to refine the action. Overall it's not that useful of a method.