Теория
Деление
Сравни поведения разных операций, связанных с делением:
/
>>> 1 / 5
0.2
>>> 25 / 4
6.25
>>> 4 / 2
2.0
>>> 5 / 0
ZeroDivisionError
//
>>> 1 // 5
0
>>> 25 // 4
6
>>> 4 // 2
2
>>> 5 // 0
ZeroDivisionError
%
(остаток)>>> 1 % 5
1
>>> 25 % 4
1
>>> 4 % 2
0
>>> 5 % 0
ZeroDivisionError
Оператор
Например, проверить чётность
|
Функции
В случае, когда много раз нужно запускать одну и ту же последовательность инструкций, ты можешь сделать функцию, чтобы избежать повторения кода.
Например, ты хочешь узнать результат сложения двойки с произведением тройки на числа 1
, 2
и 3
.
>>> 2 + 3 * 1
5
>>> 2 + 3 * 2
8
>>> 2 + 3 * 3
11
Если расширить границы любопытства за пределы 1-3
, то придётся написать ещё больше кода. Однако можно описать эту операцию для произвольного числа.
def foo(x):
return 2 + 3 * x
Имя функции — foo
, она принимает единственный аргумент и возвращает значение обобщенного выражения. Чтобы воспользоваться этой функцией, её надо вызвать.
>>> foo(1)
5
>>> foo(2)
8
>>> foo(1000)
3002
Применение функции к произвольным аргументам делается с помощью вызывающего выражения.
Вызывающие выражения
Одним из видов выражений являются вызывающие выражения. Они применяют произвольную функцию к некоторым аргументам. Как и в алгебре, математическое выражение с функцией означает получение результирующего значения из входных аргументов.
Это вызывающее выражение содержит подвыражения: оператор — выражение до скобок и разделенный запятой список операндов, содержащийся в скобках.
Выполнение вызывающего выражения:
-
Вычислить значения оператора и операндов (слева направо).
-
Вызвать функцию (значение оператора) с аргументами (значения операндов).
Если оператор и/или операнды сами по себе являются вызывающими выражениями, то эта процедура повторяется рекурсивно.
return
и print
Большинство твоих функций будут содержать инструкцию return
, которая позволяет вернуть результат вычисления туда, откуда эта функция была вызвана и завершить выполнение функции. Например, функция square
принимает число x
и возвращает его квадрат.
def square(x):
"""
>>> square(4)
16
"""
return x * x
Как только встречается инструкция return
, интерпретатор перестаёт выполнять эту функцию — выходит из неё. Если в теле функции отсутствует return
, то после выполнения всех инструкций в теле функции интерпретатор вернёт из неё значение None
.
Функция же print
используется для вывода информации в терминал. Из-за похожего поведения (в интерактивном режиме интерпретатор также выводит результат вызова функции в терминал) может возникнуть недопонимание.
Отметим, что в отличие от return
, print
не прекращает выполнение функции.
def what_prints():
print('Привет!')
return 'Тут выходим из функции.'
print('U-курс — лучший курс!')
>>> what_prints()
Привет!
'Тут выходим из функции.'
Обычно print выводит строки без кавычек, а return — с кавычками.
|
Управляющие инструкции
Булевы операторы
Python поддерживает три булевых оператора: and
, or
и not
.
>>> a = 4
>>> a < 2 and a > 0
False
>>> a < 2 or a > 0
True
>>> not (a > 0)
False
Для логических выражений определены соответствующие правила вычисления. Они используют тот факт, что результат логического выражения зачастую может быть получен без вычисления всех подвыражений этого выражения:
-
Выражение с И —
<левое> and <правое>
:-
Вычислить значение подвыражения
<левое>
. -
Если полученный результат
v
является ложным, то всё значение выражения считается равнымv
. -
В противном случае результатом всего выражения будет значение подвыражения
<правое>
.
-
-
Выражение с ИЛИ —
<левое> or <правое>
:-
Вычислить значение подвыражения
<левое>
. -
Если полученный результат
v
является истинным, то всё значение выражения считается равнымv
. -
В противном случае результатом всего выражения будет значение подвыражения
<правое>
.
-
-
Выражение с НЕ —
not <выражение>
:-
Вычислить значение выражения
<выражение>
; если полученное значение истинно, вернутьFalse
, в противном случае —True
.
-
Как думаешь, каково значение следующего выражения? Попробуй ввести его в интерпретатор.
>>> True and not False or not True and False
Человеку значение такого выражения определить непросто. Если использовать скобки, то результат будет более предсказуем. Python будет вычислять выражение как-то так:
>>> (True and (not False)) or ((not True) and False)
Такая расстановка скобок продиктована тем, что у булевых операторов (как и у арифметических) существует порядок выполнения.
-
not
обладает высшим приоритетом; -
далее следует
and
; -
or
обладает низшим приоритетом.
Булевы операторы работают не только со значениями True
и False
. Значения 0
, None
, ''
(пустая строка), []
(пустой список) интерпретатор рассматривает как ложные. Все остальные значения считаются истинными.
Оптимизации
Как думаешь, что напечатает интерпретатор в ответ на это?
>>> 1 / 0
Попробуй ввести это выражение в интерактивном режиме. Ты получишь ZeroDivisionError
— ошибку деления на ноль. А как насчёт такого?
True or 1 / 0
Результат будет True
, поскольку интерпретатор при вычислении использует оптимизации и в некоторых случаях не стремится вычислять значение каждого операнда.
Оператор | Проверяет, что… | Обрабатывает операнды слева направо, пока не встретит… | Пример |
---|---|---|---|
|
все значения истинны |
первое неистинное значение |
|
|
хотя бы одно значение истинно |
первое истинное значение |
|
Оптимизация случается, когда встречается первый операнд, позволяющий сделать суждение о всём выражении. Например, and
закончит проверять операнды как только встретит первое значение False
, поскольку одно из значений уже точно не True
.
И and , и or — оба возвращают последнее обработанное выражение. Кстати, значение этого выражения не всегда приводится к True или False .
|
Инструкция if
Условные инструкции в Python состоят из набора заголовков и наборов инструкций: обязательное предложение if
, необязательное предложение elif
и необязательное предложение else
:
if <выражение>:
<набор инструкций>
elif <выражение>:
<набор инструкций>
else:
<набор инструкций>
При выполнении условной инструкции предложения обрабатываются последовательно. Обработка подчиняется таким правилам:
-
Вычислить выражение заголовка.
-
Если полученное значение истинно, выполнить набор и проигнорировать остальные предложения.
В случае, если все предложения if
и elif
не сработали и достигнуто предложение else
, то выполняется его набор инструкций.
Инструкция while
Инструкция while
нужна для циклического исполнения некоего набора инструкций. Предложение while
состоит из заголовка и набора инструкций:
while <выражение>:
<набор>
Выполнение инструкции while
:
-
Вычислить выражение в заголовке.
-
Если результат истинен, выполнить набор инструкций и перейти к шагу 1.
На втором шаге весь набор выполняется полностью до повторного вычисления выражения в заголовке.
Для предотвращения зависания (бесконечного выполнения) набор инструкций должен что-то менять в текущем окружении.
Зависшую инструкцию while называют бесконечным циклом. Нажми Ctrl+C для его остановки.
|
Сообщения об ошибках
К настоящему времени, вероятно, ты уже видел несколько сообщений об ошибках. Хоть они и выглядят устрашающе, но сообщения об ошибках незаменимы для отладки кода. Ниже приведены некоторые распространенные типы ошибок:
- SyntaxError
-
Означает наличие синтаксической ошибки (например пропущенное двоеточие после инструкции
if
). - IndentationError
-
Появляется в случае, если в коде встречаются неправильные отступы (например некоторая строка в теле функции содержит отступ, отличающийся от всех остальных).
- TypeError
-
Возникает в случае выполнения операции с аргументами неподдерживаемого/абсурдного типа (например сложение функции и целого числа).
- ZeroDivisionError
-
Ошибка деления на ноль.
Ты сможешь лучше понять, что не так с кодом, зная описания этих ошибок. Если ошибка возникла, попробуй сообразить самостоятельно, что не так, прежде чем обращаться за помощью. Незнакомые сообщения об ошибках можно легко прогуглить и понять, чем недоволен Python.
>>> square(3, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: square() takes 1 positional argument but 2 were given
-
В последней строке указан тип ошибки —
TypeError
. -
Сообщение об ошибке объясняет, что не так — было передано 2 аргумента, тогда как
square()
может принять только один. Последняя строка самая информативная. -
Предпоследняя строка сообщает о месте возникновения ошибки — ошибка TypeError произошла в строке 1.
Практика
Для выполнения практических заданий нужно:
-
склонировать свою копию репозитория с этой лабораторной работой;
-
открыть файл
lab_01.py
в текстовом редакторе; -
открыть терминал и перейти в папку со склонированным репозиторием;
-
выполнять задания, изменяя содержимое файла
lab_01.py
.
Задания могут быть двух видов:
-
Представь-себя-пайтоном (ПСП) — требуется проанализировать последовательность выражений и/или инструкций и записать результат.
-
Напиши программу — Текстом задания и доктестами описано некоторое поведение, которого надо добиться, написав/дописав некоторый программный код.
После завершения работы над каждым вопросом требуется фиксировать изменения (делать коммит), сопровождая его вменяемым описанием сделанного, например:
Также не возбраняется в любое время проталкивать изменения на GitHub:
|
Основная часть
Эту часть практических вопросов нужно успеть сделать на занятии.
Вопрос 1: Выражения (ПСП)
Это твой первый ПСП-вопрос. Для его выполнения отыщи в начале файла lab_01.py
функцию _q_01
. Эта функция ничего не делает, но содержит доктесты с пропусками, которые нужно заполнить ответами интерпретатора Python, то есть тебя.
Проверять правильность ответов на ПСП-вопросы можно и нужно из терминала вот таким образом:
Если что-то не так, будет выведено сообщение об ошибке с указанием функции и номера строки в файле. |
Подумай и запиши, что выведет Python
при обработке следующих выражений.
>>> 3
______
>>> 2 + 3
______
>>> -16 - -16
______
>>> 3 * 4 + 1
______
>>> 3 * (4 + 1)
______
>>> 2 ** 3
______
Если в выражении будет использована неизвестная переменная, то интерпретатор так и скажет: Traceback (most recent call last): ... NameError: name 'unknown' is not defined |
>>> x = 4
>>> 3 + x
______
>>> x + y
______
>>> x, y = 1, 2
>>> 3 + x
______
>>> x + y
______
>>> from operator import mul, add
>>> mul(3, 4)
______
>>> mul(3, add(4, 1))
______
>>> pow(2, 3)
______
>>> pow(pow(2, 3), abs(-2))
______
Вопрос 2: Управляющие инструкции (ПСП)
Коммит предыдущего вопроса сделан, так ведь? Тогда переходи к функции _q_02
.
>>> def xk(c, d):
... if c == 4:
... return 6
... elif d >= 4:
... return 6 + 7 + c
... else:
... return 25
>>> xk(10, 10)
______
>>> xk(10, 6)
______
>>> xk(4, 6)
______
>>> xk(0, 0)
______
>>> def how_big(x):
... if x > 10:
... print('очень много')
... elif x > 5:
... return 'много'
... elif x > 0:
... print('мало')
... else:
... print("нисколько")
>>> how_big(7)
______
>>> how_big(12)
______
>>> how_big(1)
______
>>> how_big(-1)
______
Вывод интерпретатора может состоять из нескольких строк. |
>>> n = 3
>>> while n >= 0:
... n -= 1
... print(n)
______
Случайные факты:
|
>>> positive = 28
>>> while positive:
... print("positive?")
... positive -= 3
______
>>> positive = -9
>>> negative = -12
>>> while negative:
... if positive:
... print(negative)
... positive += 3
... negative += 3
______
Вопрос 3: Вычисление логических выражений (ПСП)
Что тут сказать? Вперёд!
>>> True and 13
______
>>> False or 0
______
>>> not 10
______
>>> not None
______
Бывает, что выражение не может быть вычислено. Например, в нём требуется произвести деление на ноль, а на ноль делить нельзя — это все знают. Что же записать в пропуск? Что-то такое: Traceback (most recent call last): ... ZeroDivisionError: division by zero |
>>> True and 1 / 0 and False
______
>>> True or 1 / 0 or False
______
>>> True and 0
______
>>> False or 1
______
>>> 1 and 3 and 6 and 10 and 15
______
>>> 0 or False or 2 or 1 / 0
______
>>> not 0
______
>>> (1 + 1) and 1
______
>>> 1/0 or True
______
>>> (True or False) and False
______
Вопрос 4: Исправь ошибку
Теперь придется не только понимать код, но и писать его — это вопрос второго типа.
Проверять правильность кода в таких вопросах нужно немного по-другому:
|
Следующий фрагмент кода не работает! Найди косячки и исправь их.
def both_positive(x, y):
"""
Возвращает True, если x и y — положительные.
>>> both_positive(-1, 1)
False
>>> both_positive(1, 1)
True
"""
return x and y > 0
Вопрос 5: Сложение цифр
Напиши функцию, которая принимает неотрицательное целое число и складывает его цифры.
Припомни как работает целочисленное деление // и модуль (остаток от деления) % .
|
def sum_digits(n):
"""
Суммирует все цифры n.
>>> sum_digits(10) # 1 + 0 = 1
1
>>> sum_digits(4224) # 4 + 2 + 2 + 4 = 12
12
>>> sum_digits(1234567890)
45
>>> x = sum_digits(123) # проверяет применение return, а не print
>>> x
6
"""
"*** ТВОЙ КОД ЗДЕСЬ ***"
Дополнительная часть
Эту часть, если есть время, можно поделать и дома.
Вопрос 6: Print vs Return
Переходи к функции _q_06
.
print (в отличие от return ) не приводит к выходу из функции!
|
>>> def ab(c, d):
... if c > 5:
... print(c)
... elif c > 7:
... print(d)
... print('foo')
>>> ab(10, 20)
______
>>> def bake(cake, make):
... if cake == 0:
... cake = cake + 1
... print(cake)
... if cake == 1:
... print(make)
... else:
... return cake
... return make
>>> bake(0, 29)
______
>>> bake(1, "беспонтовый пирожок")
______
Вопрос 7: Множители
Дополни функцию factors
, принимающую число n
и выводящую все числа, которые делят n
нацело.
Например, для 20
найдутся такие числа: 20
, 10
, 5
, 4
, 2
, 1
.
def factors(n):
"""
Выводит все числа, которые делят `n` без остатка.
>>> factors(20)
20
10
5
4
2
1
"""
"*** ТВОЙ КОД ЗДЕСЬ ***"
Вопрос 8: Нисходящий факториал
Напиши функцию falling
, вычисляющую нисходящий факториал, которая принимает два аргумента (n
и k
) и возвращает произведение k
последовательно убывающих чисел, начиная с n
.
В данном задании при определенном стечении обстоятельств может код может не заработать.
Тебе необходимо определить, что может привести к подобной ситуации и ограничить возможность её возникновения.
Для это используй инструкцию assert
.
Под условием подразумевается любое условное выражение, которое описывает возможную ошибочную ситуацию.
Текст ошибки - это сообщение, которое будет выведено после записи Допустим в программе, которую ты написал или написала, необходимо в качестве аргумента функции передавать неотрицательное число
|
def falling(n, k):
"""
Вычисляет нисходящий факториал n глубины k.
>>> falling(6, 3) # 6 * 5 * 4
120
>>> falling(4, 0)
1
>>> falling(4, 3) # 4 * 3 * 2
24
>>> falling(4, 1) # 4
4
"""
"*** ТВОЙ КОД ЗДЕСЬ ***"
Вопрос 9. Удвоение восьмёрок
Напиши функцию, которая принимает число и определяет, есть ли в цифровом его представлении пара рядом стоящих восьмёрок.
def double_eights(n):
"""
Возвращает True, если в n содержится комбинация цифр 88.
>>> double_eights(8)
False
>>> double_eights(88)
True
>>> double_eights(2882)
True
>>> double_eights(880088)
True
>>> double_eights(12345)
False
>>> double_eights(80808080)
False
"""
"*** ТВОЙ КОД ЗДЕСЬ ***"
Не забудь отправить работу на проверку:
|