* jest operatorem "splat": Pobiera listę jako dane wejściowe i rozwija ją w rzeczywiste argumenty pozycyjne w wywołaniu funkcji.
Więc jeśli uniqueCrossTabsbyło [ [ 1, 2 ], [ 3, 4 ] ], to itertools.chain(*uniqueCrossTabs)znaczy to samo, co powiedzenieitertools.chain([ 1, 2 ], [ 3, 4 ])
To oczywiście różni się od przekazywania po prostu uniqueCrossTabs. W twoim przypadku masz listę list, które chcesz spłaszczyć; co itertools.chain()robi jest powrót iterator nad połączeniem wszystkich pozycyjnych argumentów przekazać do niej, gdzie każdy argument jest iterable pozycyjny w sobie.
Innymi słowy, chcesz przekazać każdą listę uniqueCrossTabsjako argument chain(), który połączy je w łańcuch, ale nie masz list w osobnych zmiennych, więc używasz *operatora, aby rozszerzyć listę list na kilka argumentów list.
Jak zauważył Jochen Ritzel w komentarzach, chain.from_iterable()jest lepiej dostosowany do tej operacji, ponieważ zakłada na początek jedną iterowalną iterowalność. Twój kod staje się wtedy po prostu:
uniqueCrossTabs = list(itertools.chain.from_iterable(uniqueCrossTabs))