Если вы хотите разделить список на части, вы можете использовать этот трюк:
list_of_slices = zip(*(iter(the_list),) * slice_size)
Например
>>> zip(*(iter(range(10)),) * 3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]
Если количество элементов не делится на размер среза, и вы хотите заполнить список None, вы можете сделать это:
>>> map(None, *(iter(range(10)),) * 3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]
Это маленький грязный трюк
Хорошо, я объясню, как это работает. Это будет сложно объяснить, но я буду стараться изо всех сил.
Сначала немного фона:
В Python вы можете умножить список на число вроде этого:
[1, 2, 3] * 3 -> [1, 2, 3, 1, 2, 3, 1, 2, 3]
([1, 2, 3],) * 3 -> ([1, 2, 3], [1, 2, 3], [1, 2, 3])
И итератор объект может быть использован один раз так:
>>> l=iter([1, 2, 3])
>>> l.next()
1
>>> l.next()
2
>>> l.next()
3
Функция zip возвращает список кортежей, где i-й кортеж содержит i-й элемент из каждой последовательности аргументов или итераций. Например:
zip([1, 2, 3], [20, 30, 40]) -> [(1, 20), (2, 30), (3, 40)]
zip(*[(1, 20), (2, 30), (3, 40)]) -> [[1, 2, 3], [20, 30, 40]]
Символ * перед zip, используемый для распаковки аргументов. Вы можете найти более подробную информацию здесь .
Так
zip(*[(1, 20), (2, 30), (3, 40)])
фактически эквивалентно
zip((1, 20), (2, 30), (3, 40))
но работает с переменным числом аргументов
Теперь вернемся к уловке:
list_of_slices = zip(*(iter(the_list),) * slice_size)
iter(the_list)
-> преобразовать список в итератор
(iter(the_list),) * N
-> сгенерирует ссылку N на итератор the_list.
zip(*(iter(the_list),) * N)
-> передаст список итераторов в zip. Что, в свою очередь, сгруппирует их в N кортежей. Но поскольку все N элементов фактически являются ссылками на один и тот же итератор iter(the_list)
, результатом будут повторные вызовы next()
на исходном итераторе
Надеюсь, это объясняет. Я советую вам пойти с более простым для понимания решением. Я только хотел упомянуть этот трюк, потому что он мне нравится.