{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Основы программирования в Python\n", "\n", "*Алла Тамбовцева, НИУ ВШЭ*\n", "\n", "*Данный ноутбук основан на [лекции](http://nbviewer.math-hse.info/github/ischurov/pythonhse/blob/master/Lecture%202.ipynb) Щурова И.В., курс «Программирование на языке Python для сбора и анализа данных» (НИУ ВШЭ).*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Списки и цикл for" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Знакомство со списками" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Создадим список значений возраста респондентов, список `age`:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[23, 25, 32, 48, 19]" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age = [23, 25, 32, 48, 19] # возраст\n", "age" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Элементы списка перечисляются в квадратных скобках через запятую. \n", "\n", "Можем создать список имен `name`, полностью состоящий из строк:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "name = [\"Анна\", \"Виктор\", \"Дмитрий\", \"Алёна\", \"Павел\"] # имена" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "А можем создать смешанный список ‒ список, состоящий из элементов разных типов. Представим, что не очень сознательный исследователь закодировал пропущенные значения в списке текстом, написал \"нет ответа\":" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "mix = [23, 25, \"нет ответа\", 32, \"нет ответа\"] # все вместе" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Элементы разных типов спокойно уживаются в списке: Python не меняет тип элементов. Все элементы, которые являются строками, останутся строками, числа ‒ числами, а сам список будет обычным списком:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "list" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(mix)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Для тех, кто работал в R:* векторы в R очень похожи на списки в Python. Но есть важное отличие. В R, вектор, содержащий как числа, так и строки, превратился бы в текстовый вектор ‒ вектор типа `character`. Например, `mix` в R выглядел бы так:\n", "\n", " \"23\", \"25\", \"нет ответа\", \"32\", \"нет ответа\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "У списка всегда есть длина ‒ количество элементов в нем. Длина определяется с помощью функции `len()`. " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(age) # пять элементов" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Для тех, кто привык к R:* просто `len`, не `length`!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если список пустой, то, как несложно догадаться, его длина равна нулю:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "empty = []\n", "len(empty)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Раз список состоит из элементов, к ним можно обратиться по отдельности. Главное, нужно помнить, что нумерация в Python начинается с нуля, а не с единицы. Существует несколько обоснований, почему это так, с одним из них мы познакомимся чуть позже, когда будем обсуждать срезы (*slices)*." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "23" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age[0] # первый элемент age" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Порядковый номер элемента в списке называется индексом. Далее, чтобы не путаться, будем разделять термины: порядковые числительные останутся для обозначения номера элемента в нашем обычном понимании, а индексы ‒ для обозначения номера элемента в Python. Например, если нас будет интересовать элемент 25 из списка `age`, мы можем сказать, что нас интересует второй элемент или элемент с индексом 1:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[23, 25, 32, 48, 19]\n", "25\n" ] } ], "source": [ "print(age)\n", "print(age[1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если элемента с интересующим нас индексом в списке нет, Python выдаст ошибку, а точнее, исключение, `IndexError`." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "ename": "IndexError", "evalue": "list index out of range", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mage\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m7\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mIndexError\u001b[0m: list index out of range" ] } ], "source": [ "age[7]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "А как обратиться к последнему элементу списка, да так, чтобы код работал и в случае, когда мы изменим длину списка? Давайте подумаем. Длина списка `age`, как мы уже убедились, равна 5, но нумерация самих элементов начинается с нуля. Поэтому: " ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "19" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age[len(age)-1] # последний элемент - 19" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Конечно, в том, что нумерация элементов в списке начинается с нуля, есть некоторое неудобство ‒ индекс последнего элемента не совпадает с длиной списка. Но, на самом деле, обращаться к последнему элементу списка можно и по-другому: считать элементы с конца!" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "19" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age[-1] # последний элемент - он же первый с конца" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Отрицательные индексы элементов в Python ‒ абсолютно нормальная вещь. Можем так же получить второй элемент с конца:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "48" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age[-2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Изменение и добавление элементов" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Список ‒ изменяемый объект в Python. Элементы списка можно заменять, внося изменения прямо в нужный список (не создавая при этом новый):" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[32, 25, 32, 48, 19]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age[0] = 32 # заменили первый элемент на 32\n", "age" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "А еще можно дописывать элементы в конец списка. Для этого существует два метода: `.append()` и `.extend()`. Метод `.append()` используется для присоединения одного элемента, `.extend()` ‒ для добавления целого списка. Для примера создадим список `nums`:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "nums = [1, 5, 8, 9]" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 5, 8, 9, 10]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nums.append(10) # добавили 10\n", "nums" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 5, 8, 9, 10, 12, 13]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nums.extend([12, 13]) # добавили 12 и 13\n", "nums" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Приписывать значения можно и к пустому списку. Это нам пригодится, когда мы будем создавать новые списки на основе старых, используя циклы и списковые включения." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[6, 8]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L = []\n", "L.append(6)\n", "L.append(8)\n", "L" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Методы `.append()` и `.extend()` приписывают значения только в конец списка. Для добавления элементов в любое другое место существует метод `.insert()`, и мы поговорим о нем чуть позже." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Важно:** если поменять местами `.append()` и `.extend()`, код либо не будет работать (случай 1), либо будет работать не так, как хочется (случай 2)." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "'int' object is not iterable", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnums\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mextend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# случай 1: один элемент не добавится\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'int' object is not iterable" ] } ], "source": [ "nums.extend(6) # случай 1: один элемент не добавится" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 5, 8, 9, 10, 12, 13, [2, 4]]" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nums.append([2, 4]) # случай 2: добавится целый список, прямо в квадратных скобках\n", "nums" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Сразу отметим **важную деталь:** при работе со списками не нужно лишний раз ставить квадратные скобки. Да, они используются для создания списков, но если объект уже является списком, еще одни скобки будут неуместны. Другими словами, объекты `age` и `[age]` ‒ совершенно разные вещи!" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[32, 25, 32, 48, 19]\n", "[[32, 25, 32, 48, 19]]\n" ] } ], "source": [ "print(age)\n", "print([age])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Здесь `[age]` ‒ это список списков. Такой объект тоже иногда бывает полезен, но просто так создавать его не нужно. Из объекта `[age]` выбрать элемент с индексом 2 уже не получится:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "ename": "IndexError", "evalue": "list index out of range", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m[\u001b[0m\u001b[0mage\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mIndexError\u001b[0m: list index out of range" ] } ], "source": [ "[age][2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Придется сначала доставать первый (и единственный) элемент из `[age]`, а потом внутри него выбирать элемент с индексом 2." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "32" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[age][0][2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Другой способ добавлять элементы в список ‒ склеивать их, то есть использовать операцию, которая называется *конкатенацией*. В этом смысле списки очень похожи на строки, и для их конкатенации тоже используется знак `+`:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 9, 10]" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[1, 2, 3] + [9, 10]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Запись через `+` кажется очень интуитивной и заманчивой, но не стоит ей часто пользоваться, особенно, когда списки большие и когда списков много. При такой конкатенации списков происходит создание нового списка, который \"склеивается\" из отдельных частей, чего не происходит при использовании `extend`: там элементы просто дописываются в уже существующий список. Поэтому приписывание одного списка в конец другого быстрее и эффективнее делать именно через `extend`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Для примера сравним результаты. Создадим три списка, объединим их двумя способами и зафиксируем время, за которое это объединение произойдет. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "l1 = [1, 2, 3]\n", "l2 = [2, 6, 7]\n", "l3 = [0, 3, 6]" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 0 ns, sys: 0 ns, total: 0 ns\n", "Wall time: 16 µs\n" ] }, { "data": { "text/plain": [ "[1, 2, 3, 2, 6, 7, 0, 3, 6]" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time\n", "\n", "# % time - одно из магических слов Jupyter (magic)\n", "# замеряет время исполнения ячейки с кодом\n", "\n", "l1 + l2 + l3" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 0 ns, sys: 0 ns, total: 0 ns\n", "Wall time: 20.7 µs\n" ] } ], "source": [ "%%time\n", "\n", "l1.extend(l2)\n", "l1.extend(l3)\n", "l1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Кажется, что разница совсем небольшая, но не стоит забывать, что этот пример игрушечный, три списка из трех однозначных чисел." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Срезы (slices)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Мы уже познакомились с тем, как выбирать отдельные элементы из списка, однако мы еще не обсудили, как выбирать несколько элементов подряд. Такие части списков называются срезами (*slices*). Индексы элементов, которые должны войти в срез, указываются в квадратных скобках, через двоеточие (`начало` : `конец`)." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[32, 25, 32, 48, 19]\n" ] } ], "source": [ "print(age) " ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[25, 32]" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age[1:3] # левый конец включается, а правый нет" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Важно:** правый конец не включается в срез! В срез выше вошли элементы с индексами 1 и 2, элемент с индексом 3 включен не был." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если мы хотим задать только начало или конец среза, один из индексов легко можно опустить: " ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[25, 32, 48, 19]\n", "[48, 19]\n", "[32, 25]\n" ] } ], "source": [ "print(age[1:])\n", "print(age[3:])\n", "print(age[:2])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Тут мы подходим к тому, [почему](http://python-history.blogspot.ru/2013/10/why-python-uses-0-based-indexing.html) нумерация элементов в Python начинается с нуля. В частности, для удобных срезов. Если нам нужны первые два элемента списка, нам не нужно долго думать и сдвигать номера элементов на единицу, достаточно просто написать, например, `age[:2]`. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Можно ли сделать срез, который будет включать в себя весь список? Легко!" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[32, 25, 32, 48, 19]" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age[:] # опускаем все индексы" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Получить пустой срез тоже дело нехитрое: нужно, чтобы индексы начала и конца совпадали." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age[2:2] # пустой срез" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "А теперь **вопрос**. У нас есть такой срез:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[32, 25]" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age[:2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Какой срез к нему нужно добавить, чтобы получить целый список `age`?" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[32, 25, 32, 48, 19]" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age[:2] + age[2:] # срез 2:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "И это будет верно для любого индекса $k$, не только двойки." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Изменять элементы списка необязательно по одному, можно задействовать срезы." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[32, 25, 32, 48, 19]\n", "[32, 25, 26, 48, 19]\n" ] } ], "source": [ "print(age)\n", "\n", "age[1:3] = [25, 26] # заменим 1 и 2 элементы \n", "print(age)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Длина списка, на который мы заменяем срез, не обязательно должна совпадать с длиной среза. Можно взять список с большим числом элементов, тогда исходный список расширится, а можно с меньшим ‒ список сузится. Замены остальных элементов при этом не произойдет, новый срез просто \"вклинится\" в середину списка." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[32, 18, 32, 45, 48, 19]\n" ] } ], "source": [ "age[1:3] = [18, 32, 45]\n", "print(age)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[32, 18, 45, 48, 19]\n" ] } ], "source": [ "age[1:3] = [18]\n", "print(age)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Изменение списков" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "На данный момент мы достаточно хорошо познакомились со списками. Но списки не так просты, как кажется. Давайте попробуем сделать следующее: скопировать один список в другой путем присваивания." ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 8, 9, 4]\n", "[1, 8, 9, 4]\n" ] } ], "source": [ "l1 = [1, 8, 9, 4]\n", "l2 = l1 # сохранили список l1 в l2\n", "\n", "print(l1)\n", "print(l2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Пока все ожидаемо. Теперь изменим элемент списка `l2` с индексом 3:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 8, 9, 5]\n" ] } ], "source": [ "l2[3] = 5\n", "print(l2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "А теперь посмотрим на список `l1`." ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 8, 9, 5]\n" ] } ], "source": [ "print(l1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Несмотря на то, что список `l1` мы не трогали, он изменился точно так же, как и список `l2`! Что произошло? На самом деле, когда мы записали `l2 = l1`, мы скопировали не сам список, а ссылку на него. Другими словами, проводя аналогию с папкой и ярлыком, вместо того, чтобы создать новую папку `l2` с элементами, такими же, как в `l1`, мы создали ярлык `l2`, который сам по себе ничего не представляет, а просто ссылается на папку `l1`. \n", "\n", "Так как же тогда копировать списки? Во-первых, у списков есть метод `copy()`. " ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 8, 9, 4]\n", "[1, 8, 9, 100]\n" ] } ], "source": [ "# дубль два\n", "l1 = [1, 8, 9, 4]\n", "l2 = l1.copy()\n", "\n", "# теперь делаем что угодно\n", "\n", "l2[3] = 100\n", "\n", "print(l1)\n", "print(l2) # все нормально" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Во-вторых, можно сделать срез и \"срезать\" весь список:" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 8, 9, 4]\n", "[1, 8, 9, 100]\n" ] } ], "source": [ "# дубль три\n", "\n", "l1 = [1, 8, 9, 4]\n", "l2 = l1[:] # полный срез\n", "\n", "# теперь делаем что угодно\n", "\n", "l2[3] = 100\n", "\n", "print(l1)\n", "print(l2) # все нормально" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Цикл for\n", "\n", "Раз есть списки, хочется научиться пробегаться по их элементам. Например, выводить на экран не весь список `age` сразу, а постепенно, каждый элемент с новой строчки. Для этого есть циклы. Рассмотрим цикл *for*." ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "32\n", "18\n", "45\n", "48\n", "19\n" ] } ], "source": [ "for i in age:\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Как устроен цикл выше? Кодом выше мы доносим до Python мысль: пробегайся по всем элементам списка `age` (`for i in age`) и выводи каждый элемент на экран (`print(i)`). Вообще любой цикл *for* имеет такую структуру: сначала указывается, по каким значениям нужно пробегаться, а потом, что нужно делать. Действия, которые нужно выполнить в цикле, указываются после двоеточия в *for* ‒ эта часть назвается *телом* цикла. \n", "\n", "Буквы в конструкции *for* могут быть любые, совсем необязательно брать букву *i*. Python сам поймет, что мы имеем в виду, запуская цикл. Давайте, используя цикл, создадим новый список." ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2, 6, 10, 18]\n" ] } ], "source": [ "list1 = [1, 3, 5, 9]\n", "list2 = [] # новый список\n", "for l in list1:\n", " list2.append(l * 2) # добавляем в него значения из l1, умноженные на 2\n", "print(list2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Конечно, циклы нужны не только для того, чтобы работать со списками. С помощью циклом можно решить любую задачу, которая требует повторения одинаковых действий. Вспомним задачу с семинара про питона, который греется на солнышке и каждый день увеличивает время пребывания на солнце. Тогда мы решали эту задачу, перезапуская ячейку с кодом несколько раз. Теперь воспользуемся циклом." ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 1\n", "2 4\n", "3 7\n", "4 10\n", "5 13\n", "6 16\n", "7 19\n", "8 22\n", "9 25\n", "10 28\n" ] } ], "source": [ "# создадим список с номерами дней\n", "\n", "days = [2, 3, 4, 5, 6, 7, 8, 9 , 10]\n", "\n", "# начальное значение времени, которое питон проводит на солнце\n", "\n", "time = 1\n", "\n", "print(1, time)\n", "\n", "# теперь будем изменять значение time в цикле\n", "# и выводить на экран номер дня и время\n", "\n", "for d in days:\n", " time = time + 3\n", " print(d, time)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Функция range()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "На самом деле, можно было поступить еще проще. В Python есть функция `range()`, которая позволяет перебирать целые числа на заданном промежутке, не создавая при этом сам список чисел." ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "2\n", "3\n", "4\n", "5\n" ] } ], "source": [ "# пример\n", "\n", "for j in range(0, 6):\n", " print(j)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Правый конец заданного в `range()` промежутка **не включается**, будьте бдительны. В примере выше на экран были выведены числа от 0 до 5, число 6 включено не было. Применим `range()` к нашей задаче про питона:" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 1\n", "2 4\n", "3 7\n", "4 10\n", "5 13\n", "6 16\n", "7 19\n", "8 22\n", "9 25\n", "10 28\n" ] } ], "source": [ "time = 1\n", "print(1, time)\n", "\n", "for d in range(2, 11):\n", " time = time + 3\n", " print(d, time)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если мы хотим посмотреть на то, какие значения будут в `range()`, придется превратить его в список:" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "range(0, 3)" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "range(0, 3) # ни о чем" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2]" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(range(0, 3)) # значения внутри range" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Полезный факт: если нас интересуют числа на промежутке, начиная с нуля, в `range()` левый конец можно не указывать, 0 будет выбран по умолчанию." ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2, 3, 4]" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(range(5))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.2" } }, "nbformat": 4, "nbformat_minor": 2 }