[МУЗЫКА] [МУЗЫКА]
Перед тем как изучать функции, которые позволяют
генерировать итерируемые объекты, посмотрим, что еще умеют кортежи.
Например, мы хотим поменять местами значения двух переменных.
Что мы можем сделать?
Мы можем в две переменные отдельно, не используя никаких кортежей,
положить какие-то значения, а потом написать такую конструкцию a, b = b, a.
Давайте напечатаем, проверим, что действительно значения обменялись.
То есть должно вывестись 2 и 1.
Все правильно.
Что при этом происходит?
Вот эта конструкция a, b = b, a — это не то же самое,
если мы напишем a = b, а b = a.
Тогда несложно убедиться, что все значения попортятся.
Давайте проверим это.
Вот, как видно, значения испортились, но этому есть простое
объяснение: мы поменяли значения и навсегда потеряли старые.
Когда же у нас написана конструкция фактически «кортеж присвоить значение
кортеж», происходят две вещи: во-первых, создается объект типа кортеж,
содержащий в себе две наши переменные именно в таком порядке,
как они перечислены, то есть b и a.
Оно упаковывается в один объект, и затем, когда мы пишем a,
b равно этому объекту, то происходит распаковка кортежа, то есть
действия выполняются последовательно — сначала упаковываем, потом распаковываем.
В принципе, бывают и более хитрые ситуации, которые можно...
Давайте запишем с тремя переменными.
Мы можем все эти три переменные с какими-то
повторами и перестановками использовать,
они упакуются в кортеж, точно так же потом распакуются.
При этом никакие значения не испортятся,
и все будет ровно так, как мы этого ожидаем.
То есть сначала упаковка, потом — распаковка.
Теперь перейдем к генерации объектов,
которые называются iterable — итерируемые объекты.
Что такой итерируемый объект?
Это объект, из которого можно поочередно вытаскивать какие-то значения.
Например, мы хотим досчитать до миллиарда.
Если бы мы сгенерировали кортеж, который содержит в себе миллиард элементов,
то он бы занял значительную часть нашей памяти.
Но, в принципе,
досчитать от одного до миллиарда — необязательно помнить для этого все числа.
Достаточно знать текущее число и правило, по которому получаются следующие.
Вот это и есть фактически итератор.
Он знает правило, как получить следующий элемент.
Для создания таких объектов, например,
которые умеют считать от одного до миллиарда, существует функция range.
Функция range есть с одним, двумя и тремя параметрами,
они во многом похожи на срезы.
Например, если мы напишем range (10), то у нас сгенерируется объект,
iterable, содержащий правило получения
чисел от нуля до девяти, — правая граница у нас не включается,
а с одним параметром мы начинаем считать с нуля и с шагом 1, — содержащий начальный
объект 0 и правило, по которому получаются следующие объекты.
Давайте попробуем это напечатать и посмотрим, получилось у нас или нет.
Не получилось.
Оно напечатало слово range от нуля до десяти, это не совсем то, чего мы хотели.
Мы хотим получить числа от нуля до девяти.
Но для того чтобы сделать, например, из этого кортеж,
существует функция, которая называется tuple.
В Python у каждого объекта практически есть функция с таким же названием,
как называется сам объект, и она чаще всего,
если ей в качестве параметра передать что-нибудь подходящее,
генерирует нам объект нужного нам типа — tuple кортеж,
то есть мы пытаемся сделать кортеж от некоторого iterable.
И вот теперь у нас получился этот кортеж,
содержащий числа от нуля до девяти, то есть функция tuple что сделала?
Она взяла итератор первый — начальное значение, и доставала по одному.
То есть что происходит на каждом шаге?
Мы берем текущее значение и переходим к следующему объекту по правилу,
которое описано в итераторе.
В случае обычного range с одним параметром это прибавление единички к числу.
И так до тех пор, пока объекты не кончатся,
то есть iterable умеет говорить: всё, у меня все объекты внутри себя закончились.
То есть tuple вытаскивает все объекты по одному.
На самом деле iterable — это не только правило,
но и, например, тот же самый кортеж тоже является iterable.
То есть у вас, когда вы пытаетесь с кортежа что-то доставать по очереди,
у вас будут доставаться по одному элементы.
Строка тоже является итерируемым типом, например,
мы можем сделать кортеж, вызвав функцию tuple от какой-то строки.
Она может быть считанной, может быть константной.
Запустим и посмотрим.
Вот у нас получился кортеж, состоящий из букв этой строки,
то есть каждый элемент кортежа содержит ровно одну букву.
В этом случае строка интерпретирована как итерируемый объект.
Она умеет выдавать по одному все элементы,
начиная с нулевого символа, с начального символа строки.
Кортеж тоже умеет это делать.
Для перебора всех элементов чего-либо итерируемого — это может быть range,
который генерирует правило, это может быть строка,
это может быть кортеж — существует список for.
Что здесь делается?
Мы пишем слово for, затем название переменной, потом слово in — «в».
Например, цвет в кортеже,
состоящем из названий цветов: красного, зеленого и желтого.
И после этого так же, как в цикле while или в if, ставим двоеточие.
В чем смысл?
Для названия переменной — в нашем случае color, цвет,
— in и какой-то итерируемый объект.
На место color будут поочередно подставляться значения из этого
итерируемого объекта.
Давайте, например, печатать названия разноцветных яблок.
Переменную color и слово apple.
Всё.
Запускаем, смотрим, и действительно, ровно в том порядке,
как у нас были перечислены объекты в кортеже,
на место переменной color подставляются эти значения.
И вот у нас получилось три разноцветных яблока.
Конечно, очень часто for применяется не для перебора элементов какого-то кортежа,
а для перебора чисел, который мы умеем генерировать с помощью range.
Например, мы хотим напечатать все числа до 25,
то есть от нуля до 24 включительно.
Мы просто пишем какую-то переменную-счетчик и печатаем ее значения.
Вот они наши числа все напечатались.
Точно так же for может перебирать все буквы строки.
То есть если вы напишете for, название переменной, in, строка,
то у вас на место названия этой переменной поочередно будут подставляться значения
из этой строки, то есть отдельные буквы, отдельные символы.
Существует также range с двумя и тремя параметрами.
Смысл их очень похож на то, что использовалось в срезах,
то есть от какого момента мы начинаем и до какого момента идем.
Например, мы можем досчитать от 10 до 20 включительно.
Тогда нужно написать два параметра — 10 и 21,
потому что правая граница не включается.
Смотрим, немножко вылезает, давайте дальше будем
через пробел вводить, чтобы было удобнее смотреть.
Напомню, это делается с помощью sep- — separator.
Итак, два параметра так же, как в срезе, левая граница — правая граница.
Шаг по умолчанию равен единице.
В отличие от срезов, где мы могли использовать отрицательные индексы,
здесь, что такое отрицательное число, не очень понятно.
То есть, если мы напишем −10, то это будет не какой-то абстрактный
десятый с конца элемент, что такое десятое с конца число, непонятно,
это будет интерпретировано просто как число −10.
Я написал sep- — разделитель, а нужно end.
Вот теперь у нас оно отлично вывелось через пробел,
и получилось в общем-то то, чего мы ждем.
Если мы хотим считать с каким-то необычным шагом, например, посчитать,
вывести все нечетные числа до 30 включительно,
мы можем сделать range с тремя параметрами,
где третий параметр будет шаг, как и в срезе.
В случае нечетных чисел нам нужно начать с нечетного и
прибавлять каждый раз 2, чтобы получать следующее нечетное число.
Вот мы запустили и получили все нечетные числа.
При этом необязательно,
чтобы правая граница точно попадала на какое-то существующее число.
Можно, чтобы оно немного отличалось.
В любом случае, это тот момент, когда у нас счетчик станет больше,
тогда у нас все закончится, больше либо равен.
То есть подбирать специально значение, чтобы оно попало, не нужно.
Если же нам нужно посчитать справа налево, то есть в сторону уменьшения,
даже например, всего лишь до нуля, то есть мы хотим сделать все числа
от десяти до нуля включительно по убыванию,
то нам придется использовать range с тремя параметрами, да даже до 1.
Чтобы вывести все числа от десяти до нуля,
нам нужно написать начальное значение 10, а конечное значение −1,
потому что оно не входит, и шаг также сделать равный −1.
Запустим, посмотрим.
Действительно, работает.
Посмотрим еще совсем немножко, что умеет делать range.
Он может быть вложенным, то есть мы можем сделать, например, таблицу умножения так,
как она печатается на задней стороне тетрадок для младших классов.
Что для этого нужно?
Для этого нужно два цикла, один вложенный в другой,
по двум разным переменным — i и j.
Внутренний цикл будет печатать произведение i и j,
после себя ставя пробел.
И после вывода каждой строки мы будем делать пустой print,
который просто напечатает перевод строки.
Давайте посмотрим, вот оно напечаталось не очень красиво,
красоту можно навести, расставляя пробелы правильно.
Но, тем не менее, мы убедились, что действительно внутри for можно написать
другой for, но при этом не забудьте использовать другое название переменной,
чтобы у вас переменные назывались, счетчики, по-разному.
Потому что если они будут называться одинаково, вы получите совершенно не то,
чего ожидаете.
И вообще это будет выглядеть странно даже для такой задачи.
Поэтому если вдруг вам понадобилось внутри for сделать другой for, вы можете
смело это делать и также использовать if, while и любые другие конструкции,
просто как блок каких-то команд, которые выполняются определенное
количество раз или для каждого объекта, из чего-либо итерированного.
[МУЗЫКА]
[МУЗЫКА]