Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ЛЕКЦИЯ 6

.pdf
Скачиваний:
13
Добавлен:
26.03.2016
Размер:
1.66 Mб
Скачать

Лекция 6. Функции. Рекурсия.

1. Функции.

1.1.Создание функций. 1.2.Пример.

2.Области видимости.

2.1.Правила видимости имен.

2.2.Разрешение имен: правило LEGB.

2.3.Пример.

2.4.Встроенная область видимости.

2.5.Инструкция global.

2.6.Области видимости и вложенные функции.

2.7.Инструкция nonlocal.

3.Аргументы.

4.Концепции проектирования функций.

5.Рекурсивные функциии.

5.1. Применение рекурсии.

6. Анонимные функции — lambda.

6.1. Использование lambda - выражений.

1.Функции.

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

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

Если операцию необходимо будет видоизменить, достаточно будет внести изменения всего в одном месте, а не во многих.

Функции – это еще и средство проектирования, которое позволяет разбить сложную систему на достаточно простые и легко управляемые части.

Функции могут вызываться в выражениях, получать значения и возвращать результаты.

1.1.Создание функций.

Инструкция def создает объект функции и связывает его с именем: def <name>(arg1, arg2=value,... argN):

<statements>

return <value>

Функция не существует, пока интерпретатор не доберется до инструкции def и не выполнит ее. Вполне допустимо (а иногда даже полезно) вкладывать инструкции def внутрь инструкций if, циклов while и даже в другие инструкции def. Чаще всего инструкции def вставляются в файлы модулей и генерируют функции при выполнении во время первой операции импортирования.

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

Имена аргументов в строке заголовка будут связаны с объектами, передаваемыми в функцию, в точке вызова.

Инструкция return может располагаться в любом месте в теле функции – она завершает работу функции и передает результат вызывающей программе. Она является необязательной – если она

отсутствует, работа функции завершается, когда поток управления достигает конца тела функции. С технической точки зрения, функция без инструкции return автоматически возвращает объект None, однако это значение обычно просто игнорируется.

1.1.Создание функций.

Функции – это обычные объекты; они явно записываются в память во время выполнения программы. Имя функции — это ссылка на объект.

def func(): ... # Создает объект функции

othername = func # Связывание объекта функции с именем othername() # Вызов функции

Пример полиморфизма:

def times(x, y): # Создать функцию и связать ее с именем return x * y # Тело, выполняемое при вызове функции

>>>times(2, 4) # Вызов. Аргументы — числа.

8

>>>times(‘Ni’, 4) # Вызов. Аргументы — строка и число.

‘NiNiNiNi’

Это важнейшее отличие философии языка Python от языков программирования со статической типизацией, таких как C++ и Java: программный код на языке Python не делает предположений

о конкретных типах данных. Проверку типа объекта можно выполнить с помощью таких средств, как встроенная функция type, но в этом случае программный код потеряет свою

гибкость. Вообще говоря, при программировании на языке Python во внимание принимаются интерфейсы объектов, а не типы данных.

1.2.Пример.

Пересечение двух последовательностей: def intersect(seq1, seq2):

res = [] # Изначально пустой результат

for x in seq1: # Обход последовательности seq1 if x in seq2: # Общий элемент?

res.append(x) # Добавить в конец return res

>>>s1 = “SPAM”

>>>s2 = “SCAM”

>>>intersect(s1, s2) # Строки [‘S’, ‘A’, ‘M’]

Первый параметр должен обладать поддержкой циклов for, а второй – поддержкой оператора in, выполняющего проверку на вхождение. Любые два объекта, отвечающие этим условиям, будут

обработаны независимо от их типов:

>>>x = intersect([1, 2, 3], (1, 4)) # Смешивание типов (список и кортеж)

>>>x # Объект с результатом

[1]

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

>>> [x for x in s1 if x in s2] [‘S’, ‘A’, ‘M’]

2.Области видимости.

Области видимости – места, где определяются переменные и где выполняется их поиск.

Практически все, что имеет отношение к именам, включая классификацию областей видимости, в языке Python связано с операциями присваивания. Имена появляются в тот момент, когда им впервые присваиваются некоторые значения, и прежде чем имена смогут быть использованы, им необходимо присвоить значения.

Место, где выполняется присваивание, определяет пространство имен, в котором будет находиться имя, а следовательно, и область его видимости.

Помимо упаковки программного кода функции привносят в программы еще один слой пространства

имен – по умолчанию все имена, значения которым присваиваются внутри функции,

ассоциируются с локальным пространством имен этой функции. Это означает, что:

Имена, определяемые внутри инструкции def, видны только программному коду внутри инструкции def. К ним нельзя обратиться за пределами функции.

Имена, определяемые внутри инструкции def, не вступают в конфликт с именами,

находящимися за пределами инструкции def, даже если и там и там присутствуют одинаковые имена. Имя X, которому присвоено значение за пределами данной инструкции def (например, в другой инструкции def или на верхнем уровне модуля), полностью отлично от имени X, которому присвоено значение внутри инструкции def.

X = 99

def func(): X = 88

2.1. Правила видимости имен.

Функции образуют локальную область видимости, а модули – глобальную.

Любой модуль – это глобальная область видимости, то есть пространство имен, в котором создаются переменные на верхнем уровне в файле модуля. Глобальные переменные для внешнего мира становятся атрибутами объекта модуля, но внутри модуля могут использоваться как простые переменные.

Глобальная область видимости охватывает единственный файл. Имена на верхнем уровне файла являются глобальными для программного кода в этом файле. Имена всегда относятся к какому-нибудь модулю и всегда необходимо явно импортировать модуль, чтобы иметь возможность использовать имена, определяемые в нем.

Каждый вызов функции создает новую локальную область видимости - то есть пространство имен, в котором

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

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

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

внутри функции глобальным с помощью инструкции global. Если необходимо присвоить значение имени, которое находится в объемлющей инструкции def, это имя необходимо объявить внутри функции с помощью инструкции nonlocal.

Все остальные имена являются локальными в области видимости объемлющей функции, глобальными или

встроенными. Предполагается, что имена, которым не присваивались значения внутри определения функции, находятся в объемлющей локальной области видимости (внутри объемлющей инструкции def), глобальной (в пространстве имен модуля) или встроенной (предопределенные имена в модуле builtins ).

2.2.Разрешение имен: правило LEGB.

Когда внутри функции выполняется обращение к имени, интерпретатор ищет его в четырех областях видимости – в локальной (local, L), затем в локальной области любой объемлющей инструкции def (enclosing, E) или в выражении lambda, затем в глобальной (global, G) и, наконец, во встроенной (built-in, B). Поиск завершается, как только будет найдено первое подходящее имя. Если имя не будет найдено, интерпретатор выведет сообщение об ошибке.

Когда внутри функции выполняется операция присваивания (а не обращение к имени внутри выражения), интерпретатор всегда создает или изменяет имя в локальной области видимости, если в этой функции оно не было объявлено глобальным или нелокальным.

Когда выполняется присваивание имени за пределами функции (то есть на уровне модуля), локальная область видимости совпадает с глобальной – с пространством имен модуля.

2.3. Пример.

# Глобальная область видимости

X = 99 # X и func определены в модуле: глобальная область def func(Y): # Y и Z определены в функции: локальная область

# Локальная область видимости

Z = X + Y # X – глобальная переменная return Z

func(1) # func в модуле: вернет число 100

Глобальные имена: X и func.

Локальные имена: Y и Z.

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

результат сложения Z существуют только внутри функции – эти имена не пересекаются с вмещающим пространством имен модуля (или с пространствами имен любых других функций).

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

не в каком-то другом, произвольном месте внутри модуля. Кроме того, можно быть уверенным, что локальные имена не будут изменены любой другой удаленной функцией в программе, а это в свою очередь упрощает отладку программ.

2.4. Встроенная область видимости.

>> import builtins

>>> dir(builtins)

[‘ArithmeticError’, ‘AssertionError’, ‘AttributeError’, ‘BaseException’, ‘BufferError’, ‘BytesWarning’, ‘DeprecationWarning’, ‘EOFError’, ‘Ellipsis’,

...множество других имен опущено...

‘print’, ‘property’, ‘quit’, ‘range’, ‘repr’, ‘reversed’, ‘round’, ‘set’, ‘setattr’, ‘slice’, ‘sorted’, ‘staticmethod’, ‘str’, ‘sum’, ‘super’, ‘tuple’, ‘type’, ‘vars’, ‘zip’]

Согласно правилу LEGB интерпретатор выполняет поиск имен в этом модуле в последнюю очередь.

Все имена из этого списка вы получаете в свое распоряжение по умолчанию, то есть чтобы их использовать, не требуется импортировать какие-либо модули.

Внутри функции можно переопределить переменную встроенной и других областей видимости:

def hider():

open = ‘spam’ # Локальная переменная, переопределяет встроенное имя ...

open(‘data.txt’) # В этой области видимости файл не будет открыт!