{ "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 могут содержать только элементы одного типа. Если типов несколько, один тип вытесняет другой. В 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[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": [ "### Цикл for\n", "\n", "Раз есть списки, хочется научиться «пробегаться» по их элементам. Например, выводить на экран не весь список `age` сразу, а постепенно, каждый элемент с новой строчки. Для этого есть циклы. Рассмотрим цикл *for*." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "23\n", "25\n", "32\n", "48\n", "19\n" ] } ], "source": [ "for i in age:\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Как устроен цикл выше? Кодом выше мы доносим до Python мысль: \n", "\n", "* пробегайся по всем элементам списка `age` (`for i in age`);\n", "* выводи каждый элемент на экран (`print(i)`). \n", "\n", "Вообще любой цикл *for* имеет такую структуру: сначала указывается, по каким значениям нужно итерировать «пробегаться», а потом, что нужно делать. Действия, которые нужно выполнить в цикле, указываются после двоеточия в *for* – эта часть назвается *телом* цикла. \n", "\n", "Буквы в конструкции *for* могут быть любые, совсем необязательно брать букву `i`. Python сам поймет, что мы имеем в виду, запуская цикл. \n", "\n", "В качестве еще одного примера давайте для каждого элемента списка выведем на экран сообщение вида: \n", "\n", " x^2 – квадрат числа x." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "529 – квадрат числа 23\n", "625 – квадрат числа 25\n", "1024 – квадрат числа 32\n", "2304 – квадрат числа 48\n", "361 – квадрат числа 19\n" ] } ], "source": [ "# вместо i напишем a\n", "for a in age:\n", " print(a ** 2, \"– квадрат числа\", a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь, используя цикл и специальный метод `.append()`, создадим новый список на основе старого – дополним пустой список преобразованными элементами старого списка. Метод `.append()` работает просто: он приписывает элемент в конец списка. Например, так:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[23, 25, 32, 48, 19]\n", "[23, 25, 32, 48, 19, 76]\n" ] } ], "source": [ "print(age) # до\n", "age.append(76)\n", "print(age) # после" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь создадим на основе старого списка `age` список `age2` с квадратами значений возраста:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[529, 625, 1024, 2304, 361, 5776]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age2 = [] # пока пустой список\n", "for a in age:\n", " age2.append(a ** 2)\n", "age2 # сработало!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Конечно, циклы нужны не только для того, чтобы работать со списками. С помощью циклом можно решить любую задачу, которая требует повторения одинаковых действий. Вспомним задачу с семинара про питона, который греется на солнышке и каждый день увеличивает время пребывания на солнце. Тогда мы решали эту задачу, перезапуская ячейку с кодом несколько раз. Теперь воспользуемся циклом." ] }, { "cell_type": "code", "execution_count": 18, "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)" ] } ], "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.6.8" } }, "nbformat": 4, "nbformat_minor": 2 }