* является оператором «splat»: он принимает список в качестве входных данных и расширяет его до фактических позиционных аргументов при вызове функции.
Так что если uniqueCrossTabsбыло [ [ 1, 2 ], [ 3, 4 ] ], то itertools.chain(*uniqueCrossTabs)это то же самое, что сказатьitertools.chain([ 1, 2 ], [ 3, 4 ])
Это явно отличается от передачи просто uniqueCrossTabs. В вашем случае у вас есть список списков, которые вы хотите сгладить; что itertools.chain()возвращает итератор по объединению всех позиционных аргументов, которые вы ему передали, где каждый позиционный аргумент является итеративным сам по себе.
Другими словами, вы хотите передать каждый список в uniqueCrossTabsкачестве аргумента chain(), который объединит их в цепочку, но у вас нет списков в отдельных переменных, поэтому вы используете* оператор, чтобы развернуть список списков на несколько аргументов списка.
Как отметил в комментариях Йохен Ритцель, chain.from_iterable()он лучше подходит для этой операции, так как для начала предполагает наличие единственной итерации из итераций. Тогда ваш код станет просто:
uniqueCrossTabs = list(itertools.chain.from_iterable(uniqueCrossTabs))