You can do this:
spacing = [max(map(lambda x: len(str(x)), d)) for d in zip(*data)]
for row in data:
for i, elem in enumerate(row):
e = str(elem) + (',' if i < len(row) -1 else '')
print('{{:{}}} '.format(spacing[i]+1).format(e), end='')
print()
Results:
cat, 123, orange
elephant, 500000, green
horse, 123456.0, red
Explanations:
spacing is defined by first gathering the maximum lengths of each "column" in your data. We can group the columns by using:
zip(*data)
Which gives a transposed copy of your data like this:
('cat', 'elephant', 'horse'),
(123, 500000, 123456.0),
('orange', 'green', 'red')
Then we use the map function to apply the len(str(x)) function over these columns:
(3, 8, 5),
(3, 6, 8),
(6, 5, 3)
Then we just get the max of each column, combine everything in a list comprehension and return it as spacing:
spacing = [max(map(lambda x: len(str(x)), d)) for d in zip(*data)]
Then, while we loop through your data, we want to also enumerate(row) so we know which "column" we're working with. i will give you the index of the column in addition to the actual elem.
After that, we assign a temporary str to append the comma if it's not the last element:
e = str(elem) + (',' if i < len(row) -1 else '')
This makes it a bit more readable then adding it as part of the format params.
Afterwards we use string formatting (or e.ljust(spacing[i] + 1) if you wish) to add the predefined maximum spacing based on the column. Note we format the string twice by first escaping the outer curly brackets ({{ and }}), so it can be in sequence:
'{{:{}}}.format(9).format(e)
# becomes
'{:9}'.format(e)
# becomes
'cat, '
Note the use of end='' to make the print line continuous until the row has finished. The spacing[i] + 1 is to account for the added comma.
I must confess this might not be the most efficient way, but depending on what you're trying to achieve the solution can be markedly different.