Занятие 2

Практическое занятие 2: Основы языка Python

Цель: Рассмотреть основы языка Python

Задачи:

  1. Рассмотреть типы данных Python
  2. Освоить использование арифметических операций, операций сравнения, операций над строками и логичеких операций в Python
  3. Получить практику в целочисленной арифметике
  4. Освоить использование цикла while
  5. Рассмотреть многоуровневое и каскадное ветвления
  6. Познакомиться с аргументами функции range()
  7. Освоить ряд арифметических алгоритмов: определение простоты числа, разложение на простые множители и алгоритм Евклида

Типы данных Python

Рассмотрение типов данных языка Python мы начнем с числового и строкового. Числа записываются последовательностью цифр, также перед числом может стоять знак минус, а строки записываются в одинарных кавычках. Таким образом, 2 и '2' — это разные объекты, первый объект — целое число (тип int), а второй — строка (тип str). Операция + для целых чисел и для строк работает по-разному: для чисел это сложение, а для строк — конкатенация (выполните код в ячейках ниже):

In [1]:
2 + 2
Out[1]:
4
In [2]:
'2' + '2'
Out[2]:
'22'

Кроме целых чисел (тип int) есть и другой класс чисел: действительные (вещественные числа, тип float), представляемые в виде десятичных дробей. Они записываются с использованием десятичной точки, например, 2.0. Объекты 2 и 2.0 имеют равные значение, но это — разные объекты. Например, можно вычислить значения выражения 'ABC' 10 (повторить строку 10 раз), но нельзя вычислить 'ABC' 10.0:

In [3]:
'ABC' * 10
Out[3]:
'ABCABCABCABCABCABCABCABCABCABC'
In [4]:
'ABC' * 10.0
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [4], in <cell line: 1>()
----> 1 'ABC' * 10.0

TypeError: can't multiply sequence by non-int of type 'float'

Определить тип объекта можно при помощи функции type():

In [1]:
type(5)
Out[1]:
int
In [6]:
type(5.0)
Out[6]:
float
In [7]:
type('5')
Out[7]:
str
In [1]:
type(5 < 10)
Out[1]:
bool

Представление чисел в различных системах счисления

Язык Python позволяет оперировать непосредственно с числами, представленными в некоторых системах счисления. Например, с помощью префикса 0b можно записать число в двоичной системе счисления, с префиксом 0o — в восьмеричной системе, а с 0x— в шестнадцатеричной системе счисления. Исполните ячейки ниже:

In [12]:
0b11111111
Out[12]:
255
In [18]:
0b00000001 + 0b00000011
Out[18]:
4
In [ ]:
0o1234567
In [ ]:
0xffff

Функции bin(), oct() и hex() позволяют преобразовать целое число из десятичной в двоичную, восьмеричную и шестнадцатиричную системы счисления, соответственно. Результат будет представлен в виде строки цифр с соответствующим префиксом:

In [13]:
bin(168)
Out[13]:
'0b10101000'
In [14]:
oct(168)
Out[14]:
'0o250'
In [ ]:
hex(255)

Операции для чисел

В таблице ниже приведены основные перации для чисел:

Операция Действие
A + B сумма
A - B разность
A * B произведение
A / B частное
A ** B возведение в степень

Полезно помнить, что квадратный корень из числа x — это x ** 0.5, а корень степени n это x ** (1 / n). Есть также унарный вариант операции -, то есть операция с одним аргументом. Она возвращает число, противоположное данному. Например: -A.

В выражении может встречаться много операций подряд. Как в этом случае определяется порядок действий? Например, чему будет равно 1 + 2 * 3 ** 1 + 1? В данном случае ответ будет 8, так как сначала выполняется возведение в степень, затем – умножение, затем — сложение.

Более общие правила определения приоритетов операций:

  1. Выполняются возведения в степень справа налево, то есть 3 ** 3 ** 3 это $$ 3^{(3^{3})}. $$
  2. Выполняются унарные минусы (отрицания).
  3. Выполняются умножения и деления слева направо. Операции умножения и деления имеют одинаковый приоритет.
  4. Выполняются сложения и вычитания слева направо. Операции сложения и вычитания имеют одинаковый приоритет.

Задачи

Задача 1: запишите в ячейку ниже код, вычисляющий следующее выражение: $$ 2583600 + 389*487 - \frac{25^{80}}{1250} $$

In [ ]:

Задача 2: запишите в ячейку ниже код, вычисляющий следующее выражение: $$ \sqrt{98} - 3.14*\frac{25^{15^{3^{2}}}}{(153.6-17.6*9.7)} $$

In [ ]:

Библиотека math

Большое число стандартных математических функций содержится в библиотеке math. Например, приведенный ниже код подключает библиотеку math (с помощью import) и вычисляет значение квадратного корня числа 64:

import math
print(math.sqrt(64))

Выполните этот код в ячейке ниже.

In [ ]:

Задача 3: в ячейке ниже напишите код, вычисляющий следующее выражение: $$ 3,58 - \frac{\ln{89}}{358} $$

In [ ]:

Строки

Как уже сказано выше, литералы объектов типа str записываются в апострофах или в кавычках. Строкой называется последовательность символов: букв, цифр, знаков препинания и т.д.:

In [2]:
print('Это строка')
Это строка

Операции над строками

Операция Действие
A + B конкатенация
A * n повторение n раз

Значение n должно быть целым и неотрицательным.

Задача 4: запишите в ячейку ниже код, формирующий предложение из строк 'снегирей', 'расселась', 'калины', 'стайка', 'ветках', 'На', ' ' с помощью операций над строками:

In [ ]:

Целочисленная арифметика

Для целых чисел определены операции +, -, *, /, и **. Операция деления / для целых чисел возвращает значение типа float. Также функция возведения в степень возвращает значение типа float, если показатель степени — отрицательное число.

Но есть и специальная операция целочисленного деления, выполняющегося с отбрасыванием дробной части, которая обозначается //. Она возвращает целое число: целую часть частного. Например:

In [8]:
21 // 4
Out[8]:
5
In [9]:
-21 // 4
Out[9]:
-6

Обратим внимание, что совершая операцию целочисленного деления на 10 для числа, записанного в десятичной системе счисления, мы отбрасываем младший разряд (выполните код ниже):

In [40]:
152 // 10
Out[40]:
15

Другая близкая ей операция: это операция взятия остатка от деления, обозначаемая %:

In [10]:
21 % 4
Out[10]:
1
In [11]:
-21 % 4
Out[11]:
3

Объясните значение в ячейке выше.

Обратим внимание, что совершая операцию взятия остатка от деления на 10 для числа, записанного в десятичной системе счисления, мы выделяем цифру младшего разряда (выполните код ниже):

In [41]:
152 % 10
Out[41]:
2

Преобразование типов

Иногда бывает полезно целое число записать, как строку. И, наоборот, если строка состоит из цифр, то полезно эту строку представить в виде числа, чтобы дальше можно было выполнять арифметические операции с ней. Для этого используются функции, одноименные с именем типа, то есть int(), float(), str(). Например, int('123') вернет целое число 123, а str(123) вернет строку '123'. Выполните ячейку ниже и объясните полученный результат:

In [15]:
str(2 + 2) * int('2' + '2')
Out[15]:
'4444444444444444444444'

Функция преобразования типа int() может использоваться для преобразования строки, содержащей число в произвольной системе счисления в десятичное число. Например, код ниже преобразует строку с записью числа в шестнадцатиричной системе счисления в десятичное число:

In [17]:
int('0xFF', base=16)
Out[17]:
255

Префикс можно и исключить, поэкспериментируйте с преобразованием чисел из различных систем счисления, не забывая указывать основание — параметр base:

In [ ]:

Логический тип

Следующий тип - логический (bool). Величина логического типа может принимать только одно из двух значений: в Python это значения True и False. Величина типа bool является результатам перечисленных ниже операций сравнения:

Операция Действие
> Возвращает True, если первый операнд больше второго. Иначе — False.
>= Возвращает True, если первый операнд больше или равен второму. Иначе — False.
< Возвращает True, если первый операнд меньше второго. Иначе — False.
<= Возвращает True, если первый операнд меньше или равен второму. Иначе — False.
== Возвращает True, если оба операнда равны. Иначе — False.
!= Возвращает True, если оба операнда НЕ равны. Иначе — False.

Выполните код в ячейке ниже. Измените операцию сравнения в примере — посмотрите на результаты.

In [19]:
5 >= 8
Out[19]:
False

Логические операции

Выражение типа 5 >= 8 называется простым логическим выражением, так оно содержит одну операцию сравнения. Можно формировать сложные логические выражения с помощью логических операций and, or и not:

Операция Действие
and Логическое И
or Логическое ИЛИ
not Логическое отрицание

Выполните ячейку ниже для разных числовых значений — проанализируйте результаты.

In [4]:
(5 >= 8) and (8 < 9)
Out[4]:
False

В данном выражении скобки можно не ставить, поскольку приоритет логической операции ниже, чем операторов сравнения. Напишите это выражение сами:

In [ ]:

Выполните ячейку ниже для разных логических значений — проанализируйте результаты.

In [5]:
False and True
Out[5]:
False

Задачи

Задача 5: в ячейке ниже напишите код, который строит таблицу всех значений логической операции and (таблицу истинности)

Выход (первые три строки):
A, B, A and B
False, False, False
False, True, False

In [ ]:

Задача 6: в ячейке ниже напишите код, который строит такую же таблицу всех значений логической операции or

In [ ]:

Задача 7: в ячейке ниже напишите код, который строит такую же таблицу всех значений логической операции not

In [ ]:

Идентификаторы и переменные

Идентификатор — это имя некоторого объекта (переменной, функции и проч.) в программе, позволяющее отличать его от других объектов. Идентификаторы в Python не ограничены по длине и чувствительны к регистру: A и a — это разные идентификаторы. В идентификаторах допустимы только символы от A до Z в верхнем и нижнем регистре, подчеркивание _ и, кроме первого символа идентификатора, цифры от 0 до 9. Иденитификатор _1position корректен, а идентификатор 1position — нет. Для хранения промежуточных или конечных результатов в программе используются переменные. Для создания переменной в Python достаточно придуметь для нее идентификатор (имя переменной) и присвоить ей значение с помощью оператора связывания =. Например, в коде ниже создается переменная length, которая хранит значение длины стороны квадрата, а затем величина периметра квадрата сохраняется в переменной perimeter — выполните его в ячейке ниже.

length = 100
perimeter = 4 * length
print('Периметр квадрата со стороной ' + str(length) + ' равен: ' + str(perimeter))
In [ ]:

Мы назвали оператор = оператором связывания, потому что переменная в Python является лишь ссылкой на объект в памяти. При создании любой переменной (число или строка) идентификатор связывается со значением — а само значение находится где-то в оперативной памяти. При таком подходе тип переменной может изменяться в разных частях программы — выполните пример в ячейке ниже:
Пример:

x = 'abc'
print('x = ' + x + ', ' + str(type(x)))
x = 5
print('x = ' + str(x) + ', ' + str(type(x)))
In [ ]:

Если надо выполнить арифметическую операцию над переменной и полученный результат записать в ту же переменную, можно использовать краткую форму записи арифметических операций:

Полная форма Краткая форма
A = A + B A += B
A = A - B A -= B
A = A * B A *= B
A = A / B A /= B
A = A // B A //= B
A = A % B A %= B

Ввод данных с клавиатуры: функция input()

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

In [9]:
x = input()
x = 2 * x
print(x)
2
22

Если результат оказался для Вас неожиданным, то все дело в том, что функция input() возвращает текстовую строку. Для выполнения арифметических операций необходимо преобразовать результат функции input() в число с помощью функций преобразования типов int() или float():

In [28]:
x = int(input())
x = 2 * x
print(x)
Введите значение x: 5
10

Вывод данных: функция print()

Уже используемая нами для вывода значений функция print(), может выводить не только значения переменных, но и значения любых выражений. Например, допустима запись print(3 * 2) — попробуйте вычислить разные выражения в ячейке ниже:

In [ ]:

Также при помощи функции print() можно выводить значение не одного, а нескольких выражений, для этого нужно перечислить их через запятую:

In [29]:
length = 100
perimeter = 4 * length
print('Периметр квадрата со стороной ', str(length), ' равен: ', str(perimeter))
Периметр квадрата со стороной  100  равен:  400

Выводимые значение разделяются одним пробелом. Но такое поведение можно изменить: можно разделять выводимые значения любым другим символом или не разделять никак. Для этого нужно функции print() передать специальный параметр sep, равный строке, используемый в качестве разделителя. По умолчанию параметр sep равен строке из одного пробела и между значениями выводится пробел. Чтобы использовать в качестве разделителя, например, переход на новую строку, нужно передать параметр sep, равный \n:

In [3]:
length = 100
perimeter = 4 * length
print('Периметр квадрата со стороной ', str(length), ' равен: ', str(perimeter), sep='\n')
Периметр квадрата со стороной 
100
 равен: 
400

Цикл while

На прошлом занятии мы рассмотрели конструкцию цикла for. Сегодня пришло время цикла while (цикл пока).
Цикл while состоит из логического выражения (см. ниже) после ключевого слова while и тела цикла:

while логическое выражение:
    команды
    тела
    цикла
    сдвинуты
    вправо
команда_вне_цикла

Тело цикла выполняется до тех пор, пока логическое выражение истинно. Цикл while используется в тех случаях, когда число итераций заранее неизвестно.

В задачах ниже Вы должны использовать именно цикл while, так как число итераций зависит от конкретного пользовательского ввода.

Пример применения цикла while для вычисления цифр числа в семеричной системе счисления. Объясните, почему они выводятся в обратном порядке:

In [8]:
x = int('123456', base=7)
while x != 0:
    last_digit = x % 7
    print(last_digit)
    x = x // 7
6
5
4
3
2
1

Задача 8: в ячейке ниже напишите код, который вычисляет цифры числа в пятеричной системе счисления
Вход: число в пятеричной системе счисления (вводится с клавиатуры)
Выход: цифры введенного числа

In [ ]:

Задача 9: в ячейке ниже напишите код, который подсчитывает количество цифр введенного натурального числа (десятичная система счисления)

In [ ]:

Многоуровневое и каскадное ветвление

На прошлом занятии мы познакомились с конструкцией ветвления. Вспомним этот материал, решив задачу ниже:
Задача 10: напишите код, который находит большее из двух введенных с клавиатуры чисел

In [ ]:

Теперь усложним задачу, написав код, который находит большее из трех введенных с клавиатуры чисел. Решение может выглядеть, например, как в ячейке ниже — выполните его.

In [22]:
a = float(input('Введите первое число: '))
b = float(input('Введите второе число: '))
d = float(input('Введите третье число: '))
if a >= b:
    if a >= d:
        print('Большее из трех — ', a)
    else:
        print('Большее из трех — ', d)
else:
    if b >= d:
        print('Большее из трех — ', b)
    else:
        print('Большее из трех — ', d)
Введите первое число: 3
Введите второе число: 1
Введите третье число: 2
Большее из трех —  3.0

Выше пример многоуровневого ветвления — когда внутри ветки if/else одного ветвления находится другое ветвление. Глубина подобного вложения может быть любой.
Когда таких уровней вложения много программа начинает выглядеть громозко и на выручку приходит каскадная конструкция с использованием ключевых слов if, elif, else. Ветка elif выполняется только в том случае, когда проверка предыдущего условия вернула False.
Решим предыдущую задачу с помощью каскажного ветвления:

In [4]:
a = float(input('Введите первое число: '))
b = float(input('Введите второе число: '))
d = float(input('Введите третье число: '))
if a >= b and a >= d:
    print('Большее из трех — ', a)
elif d >= a and d >= b:
    print('Большее из трех — ', d)
elif b >= a and b >= d:
    print('Большее из трех — ', b)
else:
    print('Такого не может быть')
Введите первое число: 2
Введите второе число: 7
Введите третье число: 4
Большее из трех —  7.0

Задача 11: используя вложенное и каскадное ветвление, напишите код, который по введенному номеру месяца печатает его название или выводит сообщение о некорректном вводе

In [ ]:

Задача 12: используя функцию ввода с клавиатуры, напишите программу нахождения корней квадратного уровнения: $$ a*x^2 + b*x + c = 0 $$
Вход: значения коэффициентов a, b, c, который вводятся с клавиатуры
Выход: значения корней квадратного уравнения или сообщение об их отсутствии

In [ ]:

Функция range()

На прошлом занятии в заголовке цикла for мы использовали вызов функции range() с одним аргументом — числом итераций:

In [24]:
sum = 0
for i in range(5):
    sum = sum + i
print(sum)
10

В подобных примерах функция range() создает арифметическую последовательность, по значениям которой "пробегает" переменная цикла. Выполните ячейку ниже, чтобы убедиться в этом.

In [25]:
for i in range(5):
    print(i)
0
1
2
3
4

На самом деле функция имеет три параметра — range(start, stop, step):

  1. start — начальный член,
  2. stop — ограничитель (значение не включается в прогрессию!),
  3. step — шаг прогрессии (может быть отрицательным)

Примеры:

In [26]:
for i in range(1, 8, 2):
    print(i)
1
3
5
7
In [27]:
for i in range(10, 1, -3):
    print(i)
10
7
4

Параметры start и step имеют значения по умолчанию:
start = 0
step = 1

In [28]:
for i in range(2, 8):
    print(i)
2
3
4
5
6
7

Проверка числа на простоту

Напомним, что простое число (prime number) — это натуральное число больше 1, у которого есть всего два делителя: единица и само число. Проверку числа на простоту оформим в виде функции, которая будет возвращать True для простых чисел и False для составных. Алгоритм "в лоб" заключается в том, что для проверяемого числа n перебираются все натуральные числа, начиная с 2, пока не найдем делитель числа n. Если этот делитель будет равен n, то число будет простым, иначе у n есть нетривиальный делитель и число n будет составным:

def IsPrime(n):
    d = 2
    while n % d != 0:
        d += 1
    return d == n

Задача 13: Запишите в ячейку ниже код, принимающий с клавиатуры исходное число n и выводящий сообщение является ли число простым.

Используйте код функции IsPrime() — выполните её для разных значений n.

In [ ]:

Алгоритм остановится на числе, которое будет делителем числа n. Если алгоритм остановился на числе n, то число n простое, иначе — составное. Сложность этого алгоритма — $O(n)$. Lнный алгоритм можно оптимизировать, если учесть, что у любого составного числа есть собственный (то есть не равный 1) делитель, не превосходящий квадратного корня из числа. Это позволит сократить сложность алгоритма до $O(\sqrt{n})$:

ef IsPrime(n):
    d = 2
    while d * d <= n and n % d != 0:
        d += 1
    return d * d > n

Задача 14: Измените код задачи 13, использовав оптимизированный алгоритм проверки на простоту:

In [ ]:

Факторизация числа

Разложение числа на простые множители называется факторизацией. Факторизация целых чисел обеспечивается основной теоремой арифметики, в которой утверждается существование и единственность разложения любого числа на простые множители. Факторизацию числа можно осуществить методом перебора его простых делителей подобно проверки простоты числа: произвести перебор всех целых чисел от 2 до квадратного корня из факторизуемого числа n и в вычислении остатка от деления n на каждое из этих чисел. Если остаток от деления на некоторое число m равен нулю, то m является делителем n. В этом случае n сокращается на m и процедура повторяется. По достижении квадратного корня из оставшегося числа и невозможности сократить его ни на одно из меньших чисел, оно объявляется простым и также приписывается к простым сомножителям исходного числа n:

def factorize(n):
    d = 2
    while d ** 2 <= n:
        if n % d == 0:
            n //= d
            print(d)
        else:
            d += 1
    if n != 1:
        print(n)

Задача 15: Запишите в ячейку ниже код, принимающий с клавиатуры исходное число n и выводящий список простых делителей числа n.

Используйте код функции factorize() — выполните код для разных значений n.

In [ ]:

Алгоритм Евклида

Рассмотрим задачу нахождения наибольшего общего делителя двух натуральных чисел. Постановка задачи — даны два натуральных числа a и b, необходимо найти такое наибольшее число d, которое является делителем каждого из этих чисел. Задача эффективно решается с использованием алгоритма Евклида. Он основан на следующем свойстве (обозначим наибольший общий делитель чисел a и b как НОД(a, b)): $$НОД(a, b) = НОД(a-b, b)$$ Реализация алгоритма Евклида с помощью цикла while будет выглядеть следующим образом:

def euclid(a, b): 
    while a != 0 and b != 0:
        if a > b: 
            a = a - b
        else: 
            b = b - a 
    return max(a, b)

В коде выше использована встроенная функция нахождения максимума max().

Задача 16: Запишите в ячейку ниже код, принимающий с клавиатуры два числа a, b и выводящий НОД(a, b).

Используйте код функции euclid() — выполните код для разных значений пар a, b.

In [ ]:

Алгоритм выше можно оптимизировать приняв во внимание, что многократное вычитание из большего числа меньшего закончится на числе, которое является остатком от деления двух первоначальных чисел. То есть в алгоритме можно заменить операцию вычитания на взятие остатка:

def euclid_1(a, b): 
    while a != 0 and b != 0:
        if a > b:
            a = a % b 
        else:
            b = b % a 
    return max(a, b)

Задача 17: Запишите в ячейку ниже код, принимающий с клавиатуры два числа a, b и выводящий НОД(a, b).

Используйте код функции euclid_1() — выполните код для разных значений пар a, b.

In [ ]: