Цикл for перебирает все значения какой либо итерируемой последовательности. Во втором случае ты напрямую перебираешь объекты какого либо списка по порядку. А в первом ты перебираешь значения индексов этого списка. Замечу, что функция range это та же итерируемая последовательность. Она создает объект range, который можно превратить в лист функцией list. Так print(list(range(4))) выведет список [0, 1, 2, 3]. Как видно, список начался с 0, а цифра 4 в список не вошла, ибо так и задумано. Теперь возвращаясь к циклу for i in range(len(а)): print(a[i]). Например для списка a=[1, 2, 3, 4]. Его длина равна 4, значит функция range(len(a)) создаст список [0, 1, 2, 3]. Цикл for переберёт эти значения и напечатает элемент из a под индексом i. Вспомним, что индексирование списков начинается с 0. Кстати, если вызвать a[4] выдаст ошибку, ибо элемента в списке с таким индексом в списке нет.
Цикл for перебирает все значения какой либо итерируемой последовательности. Во втором случае ты напрямую перебираешь объекты какого либо списка по порядку. А в первом ты перебираешь значения индексов этого списка. Замечу, что функция range это та же итерируемая последовательность. Она создает объект range, который можно превратить в лист функцией list. Так print(list(range(4))) выведет список [0, 1, 2, 3]. Как видно, список начался с 0, а цифра 4 в список не вошла, ибо так и задумано. Теперь возвращаясь к циклу for i in range(len(а)): print(a[i]). Например для списка a=[1, 2, 3, 4]. Его длина равна 4, значит функция range(len(a)) создаст список [0, 1, 2, 3]. Цикл for переберёт эти значения и напечатает элемент из a под индексом i. Вспомним, что индексирование списков начинается с 0. Кстати, если вызвать a[4] выдаст ошибку, ибо элемента в списке с таким индексом в списке нет.