Определение функций

Предыдущим примером вызова процедурной абстракции Python была функция sqrt для вычисления квадратного корня из модуля math. Вообще говоря, мы можем скрывать детали любого вычисления с помощью определения функции. Оно требует её имя, группу параметров и тело. Также функция может явно возвращать значение. Например, простая функция, определённая ниже, возвращает квадрат значения, которое вы в неё помещаете.

>>> def square(n):
...    return n**2
...
>>> square(3)
9
>>> square(square(3))
81
>>>

Синтаксис этого определения включает имя (square) и заключённый в скобки список формальных параметров. Для этой функции n - всего лишь формальный параметр, предполагающий, что square необходим только один элемент данных для её работы. Детали, скрытые “внутри ящика”, просто вычисляют результат n**2 и возвращают его. Мы можем вызвать функцию square, попросив среду разработки Python вычислить её и поместив внутрь актуальное значение параметра (3 в данном случае). Заметьте, что вызов square возвращает целое, которое потом может быть передано другому вызову.

Мы можем реализовать нашу собственную функцию извлечения квадратного корня, используя хорошо известную технологию под названием “метод Ньютона”. Этот метод получения приблизительного значения квадратного корня представляет собой итеративное вычисление, сходящееся к правильному значению. Уравнение \(newguess = \frac {1}{2} * (oldguess + \frac {n}{oldguess})\) принимает значение \(n\) и в цикле угадывает квадратный корень, создавая каждую \(newguess\) из \(oldguess\), полученной на предыдущей итерации. Первоначальная догадка равна \(\frac {n}{2}\). Листинг 1 демонстрирует определение функции, принимающей значение \(n\) и возвращающей его квадратный корень после совершения 20 предположений. Ещё раз, детали метода Ньютона скрыты внутри определения функции, и пользователь ничего не знает о реализации, когда использует функцию по её прямому назначению. Листинг 1 также демонстрирует использование символа #, как маркера комментария. Любые символы, идущие в строке после #, игнорируются.

Листинг 1

def squareroot(n):
    root = n/2    #первоначальная догадка должна составлять 1/2 от n
    for k in range(20):
        root = (1/2)*(root + (n / root))

    return root
>>>squareroot(9)
3.0
>>>squareroot(4563)
67.549981495186216
>>>

Самопроверка

Это задание охватывает весь изложенный выше материал. Вы когда-нибудь слышали про теорему о бесконечных обезьянах? В ней утверждается, что если обезьяна будет беспорядочно нажимать на клавиши клавиатуры бесконечное количество времени, то рано или поздно напечатает заданный текст (например, полное собрание сочинений Вильяма Шекспира). Что ж, предположим, что мы заменяем обезьяну функцией на Python. Как вы думаете, сколько она потратит времени на генерирование хотя бы одного предложения из Шекспира? Выберем для проверки фразу “methinks it is like a weasel”.

Вам наверняка не захочется запускать эту программу в браузере, так что запускайте вашу любимую Python IDE. Симуляция будет выполняться с помощью функции, генерирующей строку из двадцати семи символов путём случайного выбора из двадцати шести букв алфавита + пробел. Мы напишем ещё одну функцию, которая будет оценивать каждую сгенерированную строку, сравнивая её с целью.

Третья функция будет циклично вызывать генератор и оценщик до тех пор, пока не совпадёт 100% букв. В случае несовпадения будет генерироваться новая строка целиком. Чтобы было проще следить за прогрессом программы, эта третья функция должна печатать лучшую из уже сгенерированных строк и её оценку каждые тысячу попыток.

Усложнённое задание для самопроверки

Посмотрите, сможете ли вы улучшить программу из самопроверки, сохраняя правильно стоящие буквы и изменяя всего лишь одну из оставшихся, чтобы приблизиться к результату. Алгоритм такого типа относится к классу “поиска с восхождением к вершине”, в котором результат сохраняется только в том случае, если он лучше предыдущего.

Next Section - Объектно-ориентированное программирование в Python: определение классов