def cartesian_product(X):
msg = "<STR_LIT>"<EOL>if not is_list_like(X):<EOL><INDENT>raise TypeError(msg)<EOL><DEDENT>for x in X:<EOL><INDENT>if not is_list_like(x):<EOL><INDENT>raise TypeError(msg)<EOL><DEDENT><DEDENT>if len(X) == <NUM_LIT:0>:<EOL><INDENT>return []<EOL><DEDENT>lenX = np.fromiter((len(x) for x in X), dtype=np.intp)<EOL>cumprodX = np.cumproduct(lenX)<EOL>a = np.roll(cumprodX, <NUM_LIT:1>)<EOL>a[<NUM_LIT:0>] = <NUM_LIT:1><EOL>if cumprodX[-<NUM_LIT:1>] != <NUM_LIT:0>:<EOL><INDENT>b = cumprodX[-<NUM_LIT:1>] / cumprodX<EOL><DEDENT>else:<EOL><INDENT>b = np.zeros_like(cumprodX)<EOL><DEDENT>return [np.tile(np.repeat(np.asarray(com.values_from_object(x)), b[i]),<EOL>np.product(a[i]))<EOL>for i, x in enumerate(X)]<EOL>
Numpy version of itertools.product.
Sometimes faster (for large inputs)...

Parameters
----------
X : list-like of list-likes

Returns
-------
product : list of ndarrays

Examples
--------
>>> cartesian_product([list('ABC'), [1, 2]])
[array(['A', 'A', 'B', 'B', 'C', 'C'], dtype='|S1'),
array([1, 2, 1, 2, 1, 2])]

See Also
--------
itertools.product : Cartesian product of input iterables.  Equivalent to
    nested for-loops.