- Часть I. Вводное руководство
- Глава 2. Использование интерпретатора
- 2.2. Интерпретатор и его среда
- 4.6. Определение функций
4.6. Определение функций
Мы можем создать функцию, которая будет выводить последовательность чисел Фибо-наччи с произвольной верхней границей:
>>> def fib(n):
... '''Выводит последовательность чисел Фибонначи,
... не превышающих n'''
... a, b = 0, 1
... while b < n:
... print b,
... a, b = b, a+b
...
>>> # Теперь вызовем только что определённую функцию
... fib(2000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
Ключевое слово def представляет определение функции. После него должно следовать имя функции и, в скобках, список формальных параметров. Инструкции, образующие тело функции, записываются с отступом, начиная со следующей строки. Первой инструкцией тела функции может быть строка документации (см. раздел 4.7.5). Существуют средства для автоматического создания документации, а также средства, позволяющие пользователю просматривать строки документации в интерактивном режиме. Включение строк документации в код является хорошей традицией.
Выполнение функции вводит новую таблицу имен, используемую для локальных переменных. Точнее, все присваивания переменным в теле функции сохраняются в локальной таблице имен. При ссылке на переменную, ее поиск производится сначала в локальной таблице имён, затем в глобальной и, в последнюю очередь, в таблице встроенных имён. Так, глобальным переменным нельзя прямо присвоить значение в теле функции (не упомянув их перед этим в инструкции global), хотя на них можно ссылаться.
Аргументы функции в момент вызова помещаются в локальную таблицу имен вызываемой функции. Таким образом, аргументы передаются по значению (где значение всегда является ссылкой на объект, а не его значением)1. В случае вызова функции другой функцией, также создается новая локальная таблица имен для этого вызова.
Определение функции вводит имя этой функции в текущую таблицу имен. Значение имени функции имеет тип, распознаваемый интерпретатором как определенная пользователем функция. Это значение может быть присвоено другому имени, которое затем также можно использовать в качестве функции (механизм переименования):
>>> fib
<function fib at 0x00000000024C8B38>
>>> f = fib
>>> f(100)
1 1 2 3 5 8 13 21 34 55 89
Вы можете возразить, что fib является процедурой, а не функцией. В языке Python, как и в C, процедура — всего лишь функция, которая не возвращает никакого значения. Строго говоря, процедуры все же возвращают значение, которое, скорее, не представляет большого интереса. Это значение — None (встроенное имя). Значение None обычно не выводится интерпретатором, но Вы можете его увидеть, если действительно хотите этого:
>>> print fib(0)
None
Довольно просто написать функцию, которая возвращает список чисел ряда Фибоначчи, вместо того, чтобы выводить их:
>>> def fib2(n):
... '''Возврощает список, содержащий числа ряда Фибоначчи,
... не превыщающие n'''
... result = []
... a, b = 0, 1
... while b < n:
... result.append(b)
... a, b = b, a+b
... return result
...
>>> # Теперь вызовем только что определённую функцию
... f100 = fib2(100)
>>> # Выводим результат
... f100
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Этот пример, как обычно, демонстрирует несколько новых особенностей языка Python:
1) Инструкция return выходит из функции и возвращает значение. Без аргументов return используется для выхода из середины процедуры (иначе выход происходит при достижении конца процедуры), в этом случае возвращается значение None.
2) Инструкция result.append(b) вызывает метод объектасписка result. Метод — это функция, "принадлежащая" объекту, вызывается как obj.methodname, где obj — объект (или выражение его определяющее) и methodname — имя метода, определённого для данного типа объектов. Различные типы имеют различные наборы методов. Методы различных типов могут иметь одинаковые имена, не приводя к неопределенности. (Вы можете определить собственные типы объектов — классы — и методы работы с ними.) Метод append(), используемый в примере, определен для объектов-списков. Он добавляет элемент в конец списка. В приведенном примере его использование эквивалентно записи 'result = result + [b]', но более эффективно.
- На самом деле, правильнее было бы сказать, что аргументы передаются по ссылке на объект: если передается объект, допускающий изменения, то изменения (например, добавление элементов в список) будут видны в том месте, откуда функция была вызвана.