--- title: Nested Functions in Python localeTitle: Вложенные функции в Python --- ### Пространства имен Параметры функции, а также любые переменные, которые связаны (посредством присвоения или другими операторами привязки, такими как def) в теле функции, составляют локальное пространство имен функции, также известное как локальная область. Каждая из этих переменных известна как локальная переменная функции. Переменные, которые не являются локальными, известны как глобальные переменные (при отсутствии определений вложенных функций, которые мы обсудим в ближайшее время). Глобальные переменные являются атрибутами объекта модуля, как описано в «Атрибутах объектов модуля» на стр. 140. Всякий раз, когда локальная переменная функции имеет то же имя, что и глобальная переменная, это имя в теле функции относится к локальной переменной, а не глобальный. Мы выражаем это, говоря, что локальная переменная скрывает глобальную переменную с тем же именем во всем теле функции. ### Глобальное заявление По умолчанию любая переменная, связанная внутри тела функции, является локальной переменной функции. Если функции необходимо перестроить некоторые глобальные переменные, первая утверждение функции должно быть: глобальные идентификаторы где идентификаторы - один или несколько идентификаторов, разделенных запятыми (,). Идентификаторы, перечисленные в глобальном заявлении, относятся к глобальным переменным (т. Е. Атрибутам объекта модуля), которые функция должна перестраивать. Например, счетчик функций, который мы видели в «Другие атрибуты объектов функций» на стр. 73, может быть реализован с использованием глобальной и глобальной переменных, а не атрибута объекта функции: \_count = 0 def counter (): глобальный \_count \_count + = 1 return \_count Без глобального оператора функция счетчика вызовет исключение UnboundLocal-Error, потому что \_count тогда будет неинициализированной (несвязанной) локальной переменной. Хотя глобальное заявление допускает такой вид программирования, этот стиль часто неэлегантен и нецелесообразен. Как я упоминал ранее, когда вы хотите сгруппировать какое-то состояние и какое-то поведение, объектно-ориентированные механизмы, описанные в главе 5, обычно лучше всего. Не используйте global, если тело функции просто использует глобальную переменную (включая мутацию объекта, привязанного к этой переменной, если объект изменен). Используйте глобальный оператор только в том случае, если тело функции восстанавливает глобальную переменную (обычно назначая имя переменной). В отношении стиля, не используйте глобальные, если это строго необходимо, так как его присутствие заставит читателей вашей программы предполагать, что инструкция существует для какой-то полезной цели. В частности, никогда не используйте глобальный, кроме как первый оператор в теле функции. {mospagebreak title = Вложенные функции и вложенные области} Обозначение def внутри тела функции определяет вложенную функцию, а функция, тело которой включает def, называется внешней функцией вложенной. Код в теле вложенной функции может обращаться к (но не восстанавливать) локальные переменные внешней функции, также называемой свободными переменными вложенной функции. Самый простой способ позволить вложенной функции получить доступ к значению, часто не полагаться на вложенные области, а скорее явно передавать это значение как один из аргументов функции. При необходимости значение аргумента может быть привязано, если вложенная функция определена с использованием значения по умолчанию для необязательного аргумента. Например: def percent1 (a, b, c): def pc (x, total = a + b + c): return (x \* 100.0) / total print "Проценты:", pc (a), pc (b), pc (c) Вот те же функции, что и вложенные области: def percent2 (a, b, c): def pc (x): return (x \* 100.0) / (a ​​+ b + c) print "Проценты:", pc (a), pc (b), pc (c) В этом конкретном случае процент 1 имеет крошечное преимущество: вычисление a + b + c происходит только один раз, а внутренняя функция comp2 compc трижды повторяет вычисление. Однако, если внешняя функция перепроверяет свои локальные переменные между вызовами вложенной функции, может потребоваться повторение вычисления. Поэтому целесообразно осознавать оба подхода и выбирать наиболее подходящий вариант в каждом случае. Вложенная функция, которая обращается к значениям из внешних локальных переменных, также известна как замыкание. В следующем примере показано, как построить закрытие: def make\_adder (augend): def add (добавить): return addend + augend return add Закрытие является исключением из общего правила, согласно которому объектно-ориентированные механизмы, описанные в главе 5, являются наилучшим способом объединения данных и кода. Когда вам нужно специально создавать вызываемые объекты, с некоторыми параметрами, зафиксированными во время построения объекта, замыкания могут быть проще и эффективнее классов. Например, результат make\_adder (7) - это функция, которая принимает один аргумент и добавляет 7 к этому аргументу. Внешняя функция, возвращающая замыкание, является «фабрикой» для членов семейства функций, отличающихся некоторыми параметрами, такими как значение аргумента augend в предыдущем примере и часто может помочь избежать дублирования кода. ### лямбда-выражения Если тело функции является единственным выражением выражения return, вы можете заменить функцию специальной формой выражения лямбда: Параметры лямбда: выражение Выражение лямбда является анонимным эквивалентом нормальной функции, тело которой является единственным оператором return. Обратите внимание, что синтаксис лямбда не использует ключевое слово return. Вы можете использовать выражение лямбда везде, где вы могли бы использовать ссылку на функцию. lambda иногда может быть удобно, если вы хотите использовать простую функцию в качестве аргумента или возвращаемого значения. Вот пример, который использует лямбда-выражение в качестве аргумента функции встроенного фильтра (см. Фильтр на стр. 161): aList = \[1, 2, 3, 4, 5, 6, 7, 8, 9\] низкий = 3 высокий = 7 фильтр (lambda x, l = низкий, h = высокий: h> x> l, aList) # возвращает: \[4, 5, 6\] В качестве альтернативы вы всегда можете использовать локальную команду def, которая дает объекту функции имя. Затем вы можете использовать это имя в качестве аргумента или возвращаемого значения. Вот тот же пример фильтра, в котором используется локальная команда def: aList = \[1, 2, 3, 4, 5, 6, 7, 8, 9\] низкий = 3 высокий = 7 def в _пределах (значение, l = низкий, h = высокий): return h> value> l фильтр (в пределах_ границ, aList) # возвращает: \[4, 5, 6\] Хотя лямбда иногда может быть полезна, многие пользователи Python предпочитают def, что является более общим, и могут сделать ваш код более читаемым, если вы выберете разумное имя для этой функции. {mospagebreak title = Генераторы} Когда тело функции содержит одно или несколько вхождений выхода ключевого слова, функция называется генератором. Когда вы вызываете генератор, тело функции не выполняется. Вместо этого вызов генератора возвращает специальный объект итератора, который обертывает тело функции, его локальные переменные (включая его параметры) и текущую точку выполнения, которая изначально является началом функции. Когда вызывается следующий метод этого объекта итератора, тело функции выполняет следующий оператор yield, который принимает форму: выходное выражение Когда выполняется оператор yield, выполнение функции «заморожено» с текущей точкой выполнения и локальными переменными нетронутыми, а результат следующего результата возвращается в результате следующего метода. Когда снова вызывается снова, выполнение тела функции возобновляется там, где оно было остановлено, снова до следующего оператора yield. Если тело функции заканчивается или выполняет оператор return, итератор вызывает исключение StopIteration, чтобы указать, что итерация завершена. Операторы return в генераторе не могут содержать выражения. Генератор - очень удобный способ создания итератора. Поскольку наиболее распространенный способ использования итератора - это цикл с ним с помощью инструкции for, вы обычно вызываете генератор следующим образом: для avariable в somegenerator (аргументы): Например, скажем, что вы хотите, чтобы последовательность чисел подсчитывалась от 1 до N, а затем до 1 снова. Генератор может помочь: def updown (N): для x в xrange (1, N): выход x для x в xrange (N, 0, -1): получаем x для i в updown (3): print i # prints: 1 2 3 2 1 Вот генератор, который работает как встроенная функция xrange, но возвращает последовательность значений с плавающей запятой вместо последовательности целых чисел: def frange (start, stop, step = 1.0): в то время как start