- •§0.1. Базовые знания
- •§0.2. Где достать интерпретатор языка Питон?
- •§0.3. Установка интерпретатора языка Питон в unix
- •§0.3.1. Установка/обновление Питона из грт-пакета
- •§0.3.2. Установка Питона из исходного кода
- •§0.4. Установка Питона в ос Windows
- •§0.5. Запуск программ, написанных на Питоне
- •§0.6. Среда разработки
- •§1.1. Алгоритмы и программы
- •§1.2. Языки программирования и уровни абстракции
- •Глава 1. Базовые понятия
- •§1.3. Формальные и естественные языки
- •§1.4. Интерпретаторы и компиляторы
- •§1.5. Первая программа
- •§1.6. Что такое отладка?
- •§1.6.1. Синтаксические ошибки (syntax errors)
- •§1.6.2. Ошибки выполнения (runtime errors)
- •§1.6.3. Семантические ошибки (semantic errors)
- •§1.6.4. Процесс отладки
- •Глава 2. Переменные, операции и выражения
- •§2.1. Значения и типы
- •§2.2. Преобразование типов
- •§2.3. Переменные
- •§2.4. Имена переменных и ключевые слова
- •§2.5. Выражения
- •§2.6. Выполнение выражений
- •§2.7. Операторы и операнды
- •§2.8. Порядок операций
- •§2.9. Простейшие операции над строками
- •§2.10. Композиция
- •Глава 3. Функции §3.1. Подпрограммы
- •§3.2. Вызовы функций
- •§3.3. Справочная система
- •§3.4. Импорт модулей и математические функции
- •§3.5. Композиция
- •§3.6. Создание функций
- •§3.7. Параметры и аргументы
- •§3.8. Локальные переменные
- •§3.9. Поток выполнения
- •§3.10. Стековые диаграммы
- •§3.11. Функции, возвращающие результат
- •Глава 4. Компьютерная графика
- •Глава 5. Логические выражения, условия и рекурсия §5.1. Комментарии в программах
- •§5.2. Простые логические выражения и логический тип данных
- •§5.3. Логические операторы
- •§5.4. Выполнение по условию и «пустота»
- •§5.5. Ввод данных с клавиатуры
- •§5.6. Альтернативные ветки программы (Chained conditionals)
- •§5.7. Пустые блоки
- •§5.8. Вложенные условные операторы (Nested conditionals)
- •§5.9. Рекурсия
- •§5.10. Стековые диаграммы рекурсивных вызовов
- •§5.11. Максимальная глубина рекурсии
- •§5.12. Числа Фибоначчи
- •Глава 6. Циклы
- •§6.1. Оператор цикла while
- •§6.2. Счетчики
- •§6.3. Бесконечные циклы
- •§6.4. Альтернативная ветка цикла while
- •§6.5. Табулирование функций
- •§6.6. Специальные и экранируемые символы
- •§6.7. Числа Фибоначчи и оператор цикла while
- •§6.8. Вложенные операторы цикла и двумерные таблицы
- •§6.9. Классификация операторов цикла
- •§6.10. Управляющие структуры
- •Глава 7. Строки
- •§7.1. Оператор индексирования
- •§7.2. Длина строки и отрицательные индексы
- •§7.3. Перебор и цикл for
- •§7.4. Срезы строк
- •§7.5. Сравнение строк
- •§7.6. Строки нельзя изменить
- •§7.7. Функция find
- •§7.8. Циклы и счётчики
- •§7.9. Модуль string
- •§7.10. Классификация символов
- •§10.2. Операции над словарями
- •§10.3. Методы словарей
- •§10.4. Использование псевдонимов и копирование
- •§10.5. Разряженные матрицы
- •§10.6. Подсказки
- •§10.7. Тип «длинное целое число»
- •§10.8. Подсчет букв
§5.9. Рекурсия
Разобравшись с логическими операциями и условным оператором, перейдем к изучению очень мощной концепции, которая называется рекурсией. Для того, чтобы лучше понять, где она применяется, рассмотрим задачу, которая сама приведет нас к ней.
Помимо привычных нам арифметических в математике есть и другие операции. В
частности, факториал: например, 3/=1 *2 *3 —б9. В общем виде п! — \ *...*п, где
weNu(O) 10, причем 0/ = 1 .
Растут значения факториала очень быстро, например 5/ = 120, 7/ = 5040, а
10 / = 3628800 . Поэтому логично было бы поручить вычисление факториалов компьютеру.
Прежде чем приступать к реализации функции факториала давайте проанализируем формулу, по которой она вычисляется. При условии, что мы не знаем чему равно число п
применить формулу п!—\ *...*п «в лоб» не получится. Поэтому давай-те ее
проанализируем:
п!=1*2*...*п,
(п+1)!= 1*2*...*п*(п+1)=п!*(п+1), иначе говоря:
п! = (п—\)!*п
Это уже что-то. По сути, зная значение [п— 1) /, мы можем вычислить п! всего за одну
операцию. Аналогично, {п— 1)! = (п — 2)!*{п— 1) . Попробуем реализовать эту идею на
Питоне. Мы уже говорили о том, что из тела одной функции можно вызывать другую функцию. Почему бы не попробовать вызвать из функции эту же самую функцию? Это как раз то, что нам надо, давайте попробуем:
>» def |
fact(n): |
|
|
|
|
|
|
|
|
|
|||
|
return fact(n- |
D* |
n |
|
|
|
|
|
|
||||
>» fac |
t(3) |
|
|
|
|
|
|
|
|
|
|||
File |
"<stdin>", |
line |
2, |
in |
fac |
t |
|
|
|
|
|||
[...] |
|
|
|
|
|
|
|
|
|
|
|||
File |
"<stdin>", |
line |
2, |
in |
fac |
t |
|
|
|
|
|||
Runtime |
Error: maximum |
recursion |
depth |
excee |
de |
d |
|||||||
Хм, вызывать функцию из самой себя, видимо, можно, но интерпретатор вывел длинный список обратной трассировки и сообщение об исключении: RuntimeError: maximum recursion depth exceeded- «Достигнута максимальная глубина рекурсии». Вот и упоминание рекурсии. Сформулируем определение - возможно, это нам поможет в поиске решения проблемы.
Рекурсивными функциями являются функции, получаемые в результате конечного числа применений самих себя для целочисленных значений аргумента (параметра). Важно
Читается как «три факториал».
Число п принадлежит множеству натуральных чисел, объединенному с нулем, иначе говоря, может быть равным 0, 1, 2, 3 и т.д.
59
Ревизия: 170
Логические выражения, условия и рекурсия
заметить то, что такие функции применимы лишь к целочисленным значениям, но не к дробным.
Мы передали целочисленный аргумент- 3, но возникло исключение. Видимо, мы имеем дело с семантической ошибкой: программа делает не то, что мы подразумевали. Давайте попробуем повторить выполнение нашей программы в уме.
Итак, вызов funct (3) должен вернуть funct (2) *3, далее funct (2) - это все равно что funct (1)*2; затем идет вызов funct (0), потом funct (-1). Но п- должно быть натуральным числом или нолем! Получается, что, дойдя до граничного значения области допустимых значений п, наша программа продолжает выполнять вызов функции funct () как ни в чем ни бывало, и даже не думает останавливаться. Более того, программа «не знает» чему равен 0! - мы забыли это указать, но все поправимо.
>» |
def fact(n) if n == |
0: |
|
|
|
. . . |
ret |
urn |
1 |
|
|
|
return |
f ac |
t (n- |
-1) |
*n |
>» |
fact(3) |
|
|
|
|
6 |
|
|
|
|
|
Работает! Осталось только проверить, как функция поведет себя при некорректных значениях параметра (отрицательных или дробных, например), так что не забудьте выполнить упражнение.
Упражнение. Проверьте, как функция fact () будет вести себя с отрицательными и дробными значениями параметра. Объясните, какие проблемы возникли и почему. Модифицируйте функцию так, чтобы избежать их11.
