Вложенные функции. Вложенные области видимости. Правила поиска имен в случае вложенных функций. Фабричные функции. Передача значений во вложенную функцию
Содержание
- 1. Что такое вложенные функции?
- 2. Правила поиска имен внутри функции в случае вложенных областей видимости
- 3. Примеры вложенных функций
- 4. Фабричные функции. Основные понятия. Пример
- 5. Передача данных из объемлющей области видимости во вложенную функцию с помощью аргументов по умолчанию. Пример
- Связанные темы
Поиск на других ресурсах:
1. Что такое вложенные функции?
В языке программирования Python могут использоваться вложенные функции. Это означает, что внутри инструкции def может быть другая инструкция def. Количество вложений функций произвольно. В наиболее общем случае форма объявления вложенных функций следующая:
def Fn_1(parameters1): ... def Fn_2(parameters2): ... def Fn_N(parametersN): ... return ... return return
здесь
- Fn_1, Fn_2, Fn_N – имена функций, которые соответственно получают параметры parameters1, parameters2, parametersN.
⇑
2. Правила поиска имен внутри функции в случае вложенных областей видимости
Если внутри функции, которая есть вложенной в другую функцию, объявлено имя (переменная) то действуют следующие правила:
1. В случае обращения к имени поиск этого имени осуществляется в следующей последовательности:
- поиск в локальной области видимости;
- поиск во всех объемлющих функциях в порядке изнутри наружу;
- поиск в текущей глобальной области видимости (поиск в текущем модуле);
- поиск во встроенной области видимости (модуль buildins).
2. Если внутри функции объявлено глобальное имя с помощью инструкции global, то поиск имени начинается сразу с глобальной области видимости.
3. Если к некоторому объекту используется операция присваивания по умолчанию (t = value), то эта операция:
- создает новое имя в локальной области видимости;
- изменяет имя в текущей локальной области видимости.
4. Если внутри функции определено глобальное имя (с помощью ключевого слова global), то операция присваивания:
- создает новое имя в области видимости объемлющего модуля;
- изменяет значение имени, которое было объявлено в объемлющем модуле.
5. Если внутри функции определено нелокальное имя (инструкция nonlocal), то операция присваивания:
- создает новое имя в ближайшей объемлющей функции;
- изменяет имя, которое было создано в ближайшей объемлющей функции.
⇑
3. Примеры вложенных функций
Пример 1. Дана функция SquareEquation(), которая вычисляет решения квадратного уравнения. Внутри функции помещена вложенная функция Disc(), которая вычисляет дискриминант.
# Вложенные функции import math # Функция решения квадратного уравнения, # данная функция есть объемлющей для вложенной функции Disc(). # Функция возвращает решение уравнения в виде списка def SquareEquation(a, b, c): # Вложенная функция Disc() вычисления дискриминанта def Disc(a, b, c): d = b*b-4*a*c return d # Вычислить дискриминант D = Disc(a, b, c) if D>=0: x1 = (-b - math.sqrt(D))/(2*a) x2 = (-b + math.sqrt(D))/(2*a) return [x1, x2] else: return None # Вызвать функцию для решения уравнения 2*x^2+3*x-5=0 Res = SquareEquation(2, 3, -5) if Res!=None: print('Result = ', Res) else: print('The equation has no roots')
Результат работы программы:
Result = [-2.5, 1.0]
Пример 2.
В примере реализована функция CalcComplex(), которая на основе заданного значения n реализует вложенные функции вычисления:
- суммы комплексных чисел – функция AddComplex();
- разности комплексных чисел – функция SubComplex().
Функция CalcComplex() возвращает результат в виде списка.
# Вложенные функции import math # Функция CalcComplex(), которая на основе заданного числа вызывает # вложенную функцию вычисления соответствующего выражения. def CalcComplex(n, a1, b1, a2, b2): if n==1: # Определить функцию AddComplex() - сложение комплексных чисел def AddComplex(a1, b1, a2, b2): real = a1+a2 # вещественная часть комплексного числа imag = b1+b2 # мнимая часть комплексного числа return [real, imag] # Вызвать функцию AddComplex() result = AddComplex(a1, b1, a2, b2) # вернуть результат return result if n==2: # Определить функцию SubComplex() def SubComplex(a1, b1, a2, b2): real = a1-a2 # вещественная часть imag = b1-b2 # мнимая часть return [real, imag] # Вызвать функцию SubComplex() result = SubComplex(a1, b1, a2, b2) # Вернуть результат return result # Иначе вернуть None return None # Найти сумму комплексных чисел: # (2-3*j) + (-2+5*j) Result = CalcComplex(1, 2, -3, -2, 5) # Вывести результат print("Result = ", Result)
Результат работы программы
Result = [0, 2]
⇑
4. Фабричные функции. Основные понятия. Пример
Как известно, при вызове функции создается объект этой функции. Этот объект имеет свой адрес (ссылку). В случае вложенных функций можно сохранить объект вложенной функции в объемлющей функции. Если сохранен объект вложенной функции, то такая функция называется фабричной функцией. При этом к объемлющей функции относится требование: объемлющая функция должна вернуть ссылку на объект вложенной функции в операторе return.
После объявления фабричной функции в программе, ее можно использовать следующим образом:
- создавать объект фабричной функции с помощью вызова объемлющей функции. При этом создается ссылка на объект фабричной функции. Кроме того, в объекте фабричной функции запоминаются все значения, которые были ей переданы из объемлющей функции;
- вызвать фабричную функцию с помощью созданной ссылки.
В общем случае, процесс создания и использования фабричной функции выглядит следующим образом.
1. Объявить вложенные функции как показано ниже
def Fn1(parameters1): ... def Fn2(parameters2): # это есть фабричная функция ... # использование параметров parameters1 объемлющей функции # ... ... return value # функция Fn2() возвращает некоторый результат ... return Fn2 # функция Fn1() возвращает ссылку на объект функции Fn2()
2. Получить ссылку на объект вложенной фабричной функции. Чтобы получить ссылку, нужно обратиться в объемлющую функцию Fn1() с аргументами, которые ей передаются
ref = Fn1(arguments1)
В этом случае аргументы arguments1 объемлющей функции Fn1() конвертируются в параметры parameters1. Эти параметры используются и запоминаются в объекте вложенной функции Fn2().
3. Вызвать объект фабричной функции Fn2() с помощью ссылки ref
ref(arguments2)
здесь arguments2 конвертируются в parameters2 вложенной функции Fn2.
Таким образом, в программе возникает вызов фабричной функции
Fn1(arguments1)(arguments2)
Пример 1. Функция, которая вычисляет факториал числа n: n! = 1·2·3· … ·n.
# Фабричные функции. Вычисление факториала числа # 1. Определить внешнюю функцию Factorial(n), # которая просто объявляет и возвращает вложенную функцию Fact() def Factorial(n): # Объявить вложенную функцию вычисления факториала def Fact(): # функция Fact() запоминает значение n # из объемлющей области видимости и использует его if (n<=0): return 0 i=1 res=1 while i<=n: res=res*i i=i+1 return res # Вернуть результат функции Fact() не вызывая ее return Fact # 2. Запомнить ссылку на функцию Factorial(5), # которая вычисляет 5! ref5 = Factorial(5) # Вывести ссылку print("ref5 = ", ref5) # ref5 = <function Factorial.<locals>.Fact at 0x035176A8> # Вызвать функцию вычисления факториала 5! по ссылке # и получить результат F5 = ref5() print("5! = ", F5) # 5! = 120 # 3. Получить другую ссылку на функцию, которая вычисляет 8! ref8 = Factorial(8) # Вывести ссылку ref8 и результат вычисления 8! print('ref8 = ', ref8) print("8! = ", ref8()) # 4. Сразу обратиться к функции вычисления факториала 10! по ссылке print("10! = ", Factorial(10)()) # 5. Снова вызвать функцию вычисления 5! через ссылку ref5, # ссылка ref5 запоминается print("5! = ", ref5()) # 5! = 120
Результат работы программы
ref5 = <function Factorial.<locals>.Fact at 0x032E2150> 5! = 120 ref8 = <function Factorial.<locals>.Fact at 0x033376A8> 8! = 40320 10! = 3628800 5! = 120
Пример 2. Использование фабричной функции, получающей параметры. В примере объявляются функции, которые вычисляют корень n-го степени из числа x. Объемлющая функция получает значение n, которое запоминается в фабричной функции. Фабричная функция, в свою очередь, получает параметр x.
# Вложенные функции. Фабричные функции # Получение корня n-й степени из числа x # 1. Объявить объемлющую функцию Root() с вложенной функцией Rt() def Root(n): # корень n-й степени # Объявить вложенную функцию, которая получает число x def Rt(x): # во вложенной функции запоминается параметр n объемлющей функции return x**(1.0/n) # Вернуть ссылку на вложенную функцию return Rt # 2. Запомнить ссылку на объемлющую функцию с параметром 3 ref = Root(3) # ref = <function Root.<locals>.Rt at 0x0032B588> print('ref = ', ref) # 3. Вычислить корень 3-й степени из числа 27 result = ref(27) # вызывается Root(3)(27) print('27(1/3) = ', result)
Результат работы программы
ref = <function Root.<locals>.Rt at 0x030E2150> 27^(1/3) = 3.0
⇑
5. Передача данных из объемлющей области видимости во вложенную функцию с помощью аргументов по умолчанию. Пример
Из объемлющей функции можно передать данные во вложенную функцию с помощью аргументов по умолчанию. Общая форма такой передачи следующая
def FnOut: varOut = value def FnIn(varIn = varOut): # varOut - аргумент по умолчанию # использование varIn ... return ... return
здесь
- FnOut – объемлющая функция;
- FnIn – вложенная функция;
- varOut – переменная в объемлющей функции, которая передается во внутреннюю функцию;
- value – значение, которое получает переменная varOut в объемлющей функции;
- varIn – переменная во вложенной функции, которой передается значение переменной varOut объемлющей функции. Передача значения происходит в виде строки varIn=varOut.
Пример.
В примере реализуется вычисление площади треугольника по формуле Герона. Во вложенную функцию Semiperimeter передаются три аргумента по умолчанию из функции AreaTriangle.
# Вложенные функции # Подключить математический модуль import math # Определить функцию AreaTriangle(), # которая вычисляет площадь треугольника по формуле Герона # по длинам его сторон a, b, c. def AreaTriangle(a, b, c): # Проверка, можно ли из сторон a, b, c образовать треугольник if (((a+b)<c)or((b+c)<a)or((a+c)<b)): return 0 # В функции AreaTriangle() определяется # вложенная функция Semiperimeter(), которая получает параметры a, b, c # объемлющей функции и на основе этих параметров вычисляет полупериметр. # Параметры a, b, c получаются как аргументы по умолчанию def SemiPerimeter(a=a, b=b, c=c): return (a+b+c)/2 # Вычислить полупериметер p = SemiPerimeter(a, b, c) # Вычислить площадь area = math.sqrt(p*(p-a)*(p-b)*(p-c)) return area # Продемонстрировать работу функции AreaTriangle() Area = AreaTriangle(5, 7, 3) print('Area = ', Area) Area = AreaTriangle(1, 1, 5) print('Area = ', Area)
Результат работы программы
Area = 6.49519052838329 Area = 0
⇑
Связанные темы
- Понятие функции. Общая форма. Примеры объявления и использования функций
- Области видимости имен. Локальные имена. Правила видимости имен. Правило LEGB. Ключевое слово global. Переопределение имен в функциях
⇑