Программирование для политологов

Щуров И.В., НИУ ВШЭ

Данный notebook распространяется на условиях лицензии Creative Commons Attribution-Share Alike 4.0. При использовании обязательно упоминание автора курса и аффилиации. При наличии технической возможности, необходимо также указать активную гиперссылку на страницу курса.

Исходный код этой лекции

Лекция 1. Первое знакомство

Python как калькулятор

In [1]:
4*7
Out[1]:
28
In [2]:
4*3**4
Out[2]:
324
In [3]:
4^3 #угадайте, что получится
Out[3]:
7

Решеткой обозначается комментарий. (Всё, что написано после решетки и до конца строки, игнорируется Питоном.)

Возведение в степень обозначается двумя звёздочками «**». Крышечка «^» обозначает совсем другую операцию — побидное сложение по модулю два. Вам почти наверняка эта операция никогда не понадобится. Чтобы у вас не сложилось впечатление, что это та же операция, что обычное сложение, приведем ещё один пример:

In [4]:
4^4
Out[4]:
0

Со сложением, умножением и степенью всё должно быть понятно. Деление, на первый взгляд, тоже не предвещает проблем:

In [5]:
12/3
Out[5]:
4

Однако…

In [6]:
3/2 #угадайте, что получится?
Out[6]:
1

Деление целых чисел по умолчанию — целочисленное (остаток отбрасывается). Чтобы объяснить Питону, что вы хотите получить в ответе вещественное число (точнее, «число с плавающей точкой»), нужно делитель или делимое записать как число с плавающей точкой. (Кстати, в программировании разделителем в десятичной записи всегда является точка, а не запятая.)

In [7]:
3./2
Out[7]:
1.5
In [8]:
3/2.
Out[8]:
1.5

Тот факт, что Питон по умолчанию целые числа делит целочисленно, не кажется таким уж интуитивным — он приводил к появлению разнообразных багов и стоил многих человекочасов, потраченных на отладку. В третьей версии Python операция деления будет вести себя иначе: одинарный слэш будет обозначать всегда деление с плавающей точкой, а для целочисленного деления нужно будет явно написать два слэша вместо одного. Чтобы включить тот же режим в Python версии 2, нужно ввести следующее заклинание:

In [9]:
from __future__ import division
#обратите внимание на двойные нижние подчёркивания перед и после слова future
In [10]:
2/3 #теперь результат будет более предсказуемым
Out[10]:
0.6666666666666666

Как обстоят дела с другими операциями? Попробуем извлечь квадратный корень:

In [11]:
sqrt(4)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-11-718d7f173e1d> in <module>()
----> 1 sqrt(4)

NameError: name 'sqrt' is not defined

Извлечение квадратного корня не входит в комплект математических операций, доступных в Питоне по умолчанию, поэтому вместо ответа мы получили какую-то непонятную ругань. Однако, соответствующая функция есть в стандартном модуле math. Чтобы ей воспользоваться, нужно импортировать этот модуль. Это можно сделать разными способами.

In [12]:
import math
math.sqrt(4)
Out[12]:
2.0

После того, как модуль math импортирован, вы можете узнать, какие ещё в нём есть функции. В IPython Notebook для этого достаточно ввести имя модуля, поставить точку и нажать кнопку «Tab». Вот, например, синус:

In [13]:
math.sin(0)
Out[13]:
0.0

Приведенный синтаксис может оказаться неудобным, если вам часто приходится вызывать какие-то математические функции. Чтобы не писать каждый раз слово «math», можно импортировать из модуля конкретные функции.

In [14]:
from math import sqrt
In [15]:
sqrt(4)
Out[15]:
2.0

А ещё при импорте функции можно переименовывать

In [16]:
from math import sqrt as sq
In [17]:
sq(4)
Out[17]:
2.0

Наконец, модуль можно тоже переименовать при импорте

In [18]:
import math as m
In [19]:
m.sqrt(4)
Out[19]:
2.0

Переменные

Понятие «переменной» в программировании похоже на аналогичное понятие в математике. Переменная — это ячейка памяти, обозначаемая каким-то именем. В этой ячейке могут храниться числа, строки и более сложные объекты. Мы пока поработаем немножко с числовыми переменными.

In [20]:
x=4
x
Out[20]:
4

В отличие, например, от языков C или Паскаль, в Питоне не нужно как-то специально объявлять переменную — достаточно просто присвоить ей значение, и можно пользоваться!

In [21]:
x+2
Out[21]:
6
In [22]:
x=x+2

С математической точки зрения, приведенная выше строчка кажется бессмыслицей — равенством, которое никогда не является верным. С точки зрения программирования, это команда, которая говорит «вычисли значение того, что стоит в правой части равенства, и присвой то, что получилось, переменной, стоящей в левой части равенства». Если вы знакомы с языком Pascal, вы бы написали «:=» вместо «=», но в Питоне используется синтаксис, более похожий на C — одиночное равенство означает операцию присвоения значения.

In [23]:
x
Out[23]:
6

А для проверки, равны ли выражения, используется двойное равенство. (Зачем оно нужно, мы узнаем чуть позже, когда будем проходить управляющие конструкции.)

In [24]:
x==6
Out[24]:
True
In [25]:
x==7
Out[25]:
False

Практичекое задание: числа Фибоначчи

Числа Фибоначчи или последовательность Фибоначчи» — последовательность чисел, начинающаяся с двух единиц, и такая, что очередное число в этой последовательности равно сумме двух предыдущих. Формально можно определить её следующим образом:

\(a_1=1\);

\(a_2=1\);

\(a_{n+1}=a_n+a_{n-1}\) для всех \(n>2\).

Например, \(a_3=1+1=2\), \(a_4=2+1=3\).

Задача: посчитать 15-е число Фибоначчи

In [26]:
aprev=1
aprevprev=1
i=2

Мы будем хранить два последних числа, поскольку именно они определяют следующее, а также номер последнего найденного числа (переменная i).

In [27]:
anext=aprev+aprevprev #нашли следующее число
i=i+1 #увеличили i на 1
print i, anext #команда print выводит на экран значение переменных и всякие другие штуки
aprevprev=aprev
aprev=anext
3 2

Питон выполняет команды последовательно, строчку за строчкой, поэтому порядок следоавния команд очень важен. Выполняя эту ячейку несколько раз, вы будете получать каждый раз очередное число Фибоначчи.

Контрольный вопрос. Что произойдёт, если мы поменяем местами две последние строчки?

Циклы: while

Код, который мы написали, выполняя предыдущее задание, работал довольно неплохо, но если бы нам нужно было найти не 15-е, а 115-е число Фибоначчи, мы бы замучались перезапускать ячейку. Чтобы объяснить Питону, что вы хотите повторить некоторый набор действий много раз, необходимо использовать циклы.

Мы рассмотрим сейчас самый простой цикл, который назыается while. Он заставляет Питон выполнять кусок кода, до тех пор, пока некоторое условие не станет ложным. Вот так нужно модифицировать наш код, чтобы нам не приходилось запускать одну и ту же ячейку много раз.

In [28]:
aprev=1
aprevprev=1
i=2
while i<15:
    anext=aprev+aprevprev
    i=i+1
    aprevprev=aprev
    aprev=anext    
print i, anext
15 610

Посмотрим более подробно на этот код. В четвертой строчке написан оператор цикла while, затем приведено условие — тело цикла будет повторяться до тех пор, пока это условие верно. (Если условие неверно с самого начало, тело цикла не будет выполнено ни разу! Это так называемый «цикл с предусловием». Если вы знаете, что такого «цикл с постусловием» (do-while), вам, возможно, будет интересно узнать, что в Питоне таких циклов нет вовсе.) В конце строчки с оператором while стоит двоеточие — это важная штука, без неё ничего не заработает.

Тело цикла — как раз тот самый блок кода, который выполняется в цикле несколько раз (где «несколько» может означать 0, 1 и больше). В большинстве языков программирование считается правилом хорошего тона выделять тело цикла (и другие блоки кода) увеличением отступа — это делает код более читабельным. Но раньше это было не более, чем пожелание — обработчики программ (интерпретаторы и компиляторы) игнорировали эти отступы, а полагалаись на другие маркеры начала и конца блока кода (фигурные скобки в C, ключевые слова begin-end в Паскале и т.д.) Создатель Питона решил, что в его языке отступ будет единственным способом показать, где начинается и где заканчивается блок — в результате, нет никакой возможности писать код без отступов. Что, на самом деле, хорошо.

Из куска кода выше видно, что четыре строчки после while принадлежат телу цикла, а последняя строчка (print) — не принадлежит. Поэтому ответ будет выведен только один раз.

Мы могли бы сделать вывод нашей небольшой программы более красивым:

In [29]:
print "a[%i] = %i" % (i, anext)
a[15] = 610

Здесь используется так называемые интерполяция строк — в строчку "a[%i] = %i" на место маркеров %i подставляется значение переменных i и next, после чего получившаяся строчка выводится на печать. (Маркер %i означает, что на его место будет подставлено целое (integer) число.)

Замечание. Код, вычисляющий числа Фибоначчи выше, не является «хорошим» ни в каком разумном смысле. Он демонстрирует, как работают переменные и циклы, но его не следует воспринимать как часть руководства по хорошему стилю программирования. Чуть попозже мы перепишем этот код более красивым, лаконичным и эффективным образом, но для этого нам нужно будет познакомиться с другими понятиями языка Python.

Упражнения

Задание 1

Вычислить с помощью Питона:

  1. \(\sin^2 2+\cos^2 2\)
  2. \(4\arctan 1\)
  3. \(e^{\frac{\ln 4}{2}}\)

Задание 2

Модифицировать программу выше таким образом, чтобы она выводила

  1. Самое большое число Фибоначчи, не превосходящее 1000.
  2. Первые 20 чисел Фибоначчи
  3. Отношение \(a_{n+1}/a_{n}\), где \(a_n\) — \(n\)-число Фибоначчи, для всех \(n\) от 1 до 1000. Как вы думаете, есть ли предел у этой последовательности?

Задание 3

Определение. Гармоническим рядом называется последовательность вида

\(b_1=1\)

\(b_2=1+\frac{1}{2}\)

\(b_n=1+\frac{1}{2}+\frac{1}{3}+\cdots+\frac{1}{n}\)

Задание. Написать программу, которая выведет на экран

  1. Первые 20 членов последовательности \(b_n\).
  2. Значение \(b_{100}\).
  3. Такое наименьшее \(n\), что \(b_n>15\).

Задание 4

Напишите программу, выводящую на экран таблицу умножения.

Подсказка. Циклы можно вкладывать друг в друга, то есть в теле цикла может быть ещё один цикл.

Задание 5

Определение. Биномиальным коэффициентом (числом сочетаний из \(n\) элементов по \(k\) элементов) называется такая штука:

\[C_{n}^k=\frac{n!}{k!(n-k)!},\]

где \(n!=1\cdot 2\cdots n\) — факториал (произведение всех натуральных чисел от 1 до n).

Задание.

Напишите программу, которая бы выводила на экран:

  1. Значение \(C_{10}^7\)
  2. Треугольник Паскаля до 15-й строчки, то есть табличку, в которой на \(n\)-й строке написаны все биномиальные коэффициенты \(C_n^k\) для всех целых неотрицательных \(k < n\).

Подсказка. Чтобы оператор print не добавлял перевод строки, можно добавить в конце запятую:

In [30]:
print "Hello ",
print "World!"
Hello  World!

In [31]:
print "Hello"
print "World!"
Hello
World!