ЛЕКЦИЯ 6
.pdfЛекция 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’) # В этой области видимости файл не будет открыт!