From the official documentation:
Q.dims
: List keeping track of shapes for individual components of a multipartite system (for tensor products and partial traces).
In other words, you can think of it as the dimensions of the (matrix representation of) the object under consideration, taking into account the tensorial structure of the underlying space.
The first element tells you about the number of rows while the second element tells you about the number of columns.
Consider as an example
fooQ = qutip.tensor(qutip.basis(2, 0), qutip.basis(2, 1))
This is the tensor product of two qubit ket states, thus it's a vector in a space of dimension $2\times 2$. As a matrix, you can represent it as a $4\times 1$ matrix. But if you want to remember the tensor structure of this space, which makes it easier to do things such as partial tracing, it's better to store each individual dimension. You then end up with fooQ.dims == [[2, 2], [1, 1]]
, because there are $2\times 2$ rows, and $1=1\times 1$ column.
In your example, [[2, 4], [2, 4]]
represents a density matrix in a space $\mathcal H_1\otimes\mathcal H_2$ with $\dim\mathcal H_1=2$ and $\dim\mathcal H_2=4$.
You can retrieve the overall dimensions of the space by doing e.g.
number_of_rows = np.prod(fooQ.dims[0])
number_of_cols = np.prod(fooQ.dims[1])
Or you can "unravel" the dimensions, obtaining a list of the dimensions of each individual component space, with
unravelled_dimensions = np.transpose(fooQ.dims)