I have a symmetric function get_corr which consumes two strings, and returns a double. 
def get_corr(id1, id2):
    # some magic to find double x
    #...
    return x
I also have a list of strings factors, with which I want to generate a symmetric matrix of size len(factors)xlen(factors) by applying get_corr to the cartesian product of factors with itself. 
This would be very easy by just using nested for loops, iterating over the indices of factors to call get_corr for each position. 
corr_matr = np.identity(factor_length)
for i in factor_length:
    for j in factor_length:
        corr_matr[i,j] = corr_matr[j,i] = get_corr(factors[i], factors[j])
But I felt like there must be some syntactic NumPy sugar for this - is there? I don't reckon it can be any faster but perhaps I'm wrong. Nested for loops for this purpose seems like it just probably isn't necessary. I attempted to use np.frompyfunc and call that on the itertools.product, but this seems worse really because I'll be calling get_corr twice as many times. Furthermore, I could not vectorize the function properly with the tuple sequence produced by itertools.product.
 
     
    