To masz stąd: http://docs.python.org/tutorial/datastructures.html#nested-list-comprehensions, więc troszkę wyżej masz właściwie wszystko co potrzebne ;) Nic poza zagnieżdżone pętle
Generujesz listę, wg. "zaleceń"; to co napisałeś możesz sobie rozbić, najpierw "zewnętrzną część":
[i for i in range(4)]
Jeśli to sobie uruchomisz, to otrzymasz listę [0, 1, 2, 3]
, zgadza się? A teraz jeśli zamiast tego i
dasz tam sobie:
[row[i] for row in matrix]
To to tak, jakbyś wywołał to dla kolejnych wartości z wcześniej otrzymanej listy. Czyli będziesz miał cztery najprostsze przypadki:
[row[0] for row in matrix]
[row[1] for row in matrix]
[row[2] for row in matrix]
[row[3] for row in matrix]
Każde z tych wyrażeń wyciąga wartość z podanej kolumny (0,1,2,3) dla każdego kolejnego wiersza. Czyli jakbyś sobie wziął [row[0] for row in matrix]
to otrzymasz: [1, 5, 9]
itd.
Na upartego to można by sobie przeczytać:
wygeneruj listę | [[row[i] for row in matrix] for i in range(4)]
która jest tworzona wg. danych z pętli | [[row[i] for row in matrix] for i in range(4)]
której kolejnymi elementami będą listy | [[row[i] for row in matrix] for i in range(4)]
zbudowane wg. wyrażenia | [[row[i] for row in matrix] for i in range(4)]
ot, tyle...
zip'a masz też w dokumentacji opisanego zip([1, 2, 3], [4, 5, 6])
da wynik [(1, 4), (2, 5), (3, 6)]
, czyli bierze z podanych sekwencji to, co na pierwszym miejscu i tworzy krotkę (1, 4), bierze to co na drugiej... itd.
Tam masz jedynie do przeczytania http://docs.python.org/tutorial/controlflow.html#tut-unpacking-arguments
mając:
matrix = [
... [1, 2, 3, 4],
... [5, 6, 7, 8],
... [9, 10, 11, 12],
... ]
uzywasz zip(*matrix)
rozpakowując matrix na kolejne elementy; to właściwie mógłbyś sobie zapisać jako:
zip([1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12])