In an isympy session (where x, y are already defined)
In [1]: coor = symbols('x y')
In [2]: coor
Out[2]: (x, y)
coor is a tuple
In [3]: xx = [coor[0]**2, coor[1]]
In [4]: xx
Out[4]:
⎡ 2 ⎤
⎣x , y⎦
xx is a list containing 2 sympy objects.
If we make an object dtype array, we can assign sympy elements:
In [5]: xy = np.empty((2,2),object)
In [6]: for i in range(2):
...: for j in range(2):
...: xy[i,j] = xx[i]*xx[j]
...:
In [7]: xy
Out[7]:
array([[x**4, x**2*y],
[x**2*y, y**2]], dtype=object)
Or a list comprehension way of creating the same
In [8]: [[i*j for j in xx] for i in xx]
Out[8]:
⎡⎡ 4 2 ⎤ ⎡ 2 2⎤⎤
⎣⎣x , x ⋅y⎦, ⎣x ⋅y, y ⎦⎦
As nested list and then array as before:
In [9]: np.array(_)
Out[9]:
array([[x**4, x**2*y],
[x**2*y, y**2]], dtype=object)
Object dtype arrays come up often on SO questions, but usually when creating 'ragged' arrays. They don't have the speed or computing power of numeric dtype arrays.
Some basic math does work with object dtype arrays, as long as the elements themselves implement the right methods (such as addition)
In [10]: xy.sum(axis=1)
Out[10]: array([x**4 + x**2*y, x**2*y + y**2], dtype=object)
In [11]: np.exp(xy)
...
TypeError: loop of ufunc does not support argument 0 of type Pow which has no callable exp method
(no one implements a exp method.)
sympy runs in python, so basic python structures like tuples and lists are natural. The interaction with numpy is hit-or-miss, and never as fast as the pure numeric arrays. sympy's own matrix/array imports usually will give you more power, but require more study.
The sympy.Matrix object given in the other answer:
In [20]: zz = zeros(2,2)
In [21]: for i in range(2):
...: for j in range(2):
...: zz[i,j] = xx[i]*xx[j]
...:
In [22]: zz
Out[22]:
⎡ 4 2 ⎤
⎢ x x ⋅y⎥
⎢ ⎥
⎢ 2 2 ⎥
⎣x ⋅y y ⎦
Can also be constructed from the nested list:
In [23]: Matrix(Out[8])
Out[23]:
⎡ 4 2 ⎤
⎢ x x ⋅y⎥
⎢ ⎥
⎢ 2 2 ⎥
⎣x ⋅y y ⎦