Many of the main numpy operators, such as np.add , np.subtract , np.multiply , etc., are called universal functions (ufuncs) , and have (among other things) the .outer method:
import numpy as np a = np.arange(3) b = np.arange(5) c = np.add.outer(a, b) print(repr(c))
Another very powerful technique for this kind of thing is broadcasting :
print(repr(a[:, None] + b[None, :])) # array([[0, 1, 2, 3, 4], # [1, 2, 3, 4, 5], # [2, 3, 4, 5, 6]])
Indexing with None (or alternatively with np.newaxis ) inserts a new dimension, so a[:, None] has the form (3, 1) and b[None, :] a[:, None] b[None, :] has the form (1, 5) . Broadcast “expands” the result by the size of a singleton, so that it has the form (3, 5) .