Как сделать вызов функции из другого файла в python?
Чтобы сделать вызов функции из другого файла в python, ее необходимо сначала импортировать. Вы можете импортировать как весь файл(модуль), так и отдельно функции из него. Для импорта, каталог, в котором лежит файл, должен быть пакетом(package), то есть содержать в себе файл init.py .
Импорт модуля. В таком случае функции из модуля вызываются через точку:
from my_package import my_module # где my_package - пакет # my_module - искомый файл def main(): x = my_module.function() .
Импорт конкретной функции из модуля:
from my_package.my_module import function def main(): x = function() .
Функции в Python
Функция — это группа связанных инструкций, выполняющих определенную задачу.
Функции помогают разбить нашу программу на более мелкие части. По мере того, как наша программа становится все больше и больше, функции делают ее более организованной и управляемой.
Кроме того, функцию можно вызвать из различных мест программы, что позволяет избежать повторения программного кода.
Синтаксис функции
def имя_функции(аргументы):
"""строка документации"""
операторы
Давайте рассмотрим какие компоненты включает в себя определение функции:
- Ключевое слово def — начало заголовка функции.
- Имя функции — для однозначной идентификации функции. Оно соответствует правилам называния идентификаторов в Python.
- С помощью параметров (аргументов) мы передаем значения в функцию. Аргументов может и не быть.
- Двоеточие : обозначает конец заголовка функции.
- Необязательная строка документации (docstring) нужна для описания того, что делает функция.
- Один или несколько операторов Python составляют тело функции. Все инструкции должны иметь одинаковый отступ (4 пробела или 1 TAB).
- Оператор return возвращает переданное значение из функции. Он необязателен.
Пример функции
def greet(name): """ Эта функция приветствует человека, имя которого хранится в параметре name. """ print("Привет, " + name + ". Доброе утро!")
Как вызвать функцию
После того, как мы определили функцию, мы можем вызвать ее в программе или даже из командной строки Python. Чтобы вызвать функцию, мы просто вводим ее имя с соответствующими параметрами.
>>> greet('Джон') Привет, Джон. Доброе утро!
Примечание. Попробуйте сами запустить приведенный выше код с определением функции и посмотрите результат.
def greet(name): """ Эта функция приветствует человека, имя которого хранится в параметре name. """ print("Привет, " + name + ". Доброе утро!") greet('Джон')
Строки документации
Первая строка после заголовка функции называется строкой документации, она описывает, что делает функция.
Документирование кода — не обязательная, но очень хорошая практика. Если вы не помните, что ели на ужин на прошлой неделе, всегда документируйте свой код.
В приведенном выше примере у нас есть строка документации сразу под заголовком функции. Обычно используют тройные кавычки, чтобы документация могла занимать несколько строк. Получить доступ к строке документации можно через атрибут __doc__ .
Пример строки документации
Попробуйте запустить в оболочке Python следующую команду и посмотрите на результат.
>>> print(greet.__doc__) Эта функция приветствует человека, имя которого хранится в параметре name.
Возвращаемое значение
Оператор return используется для выхода из функции и возврата в то место, откуда она была вызвана.
Синтаксис возвращения значения
return список_выражений
Оператор return может содержать выражение, которое возвращает значение. Если в операторе нет выражения или самого оператора возврата нет внутри функции, функция вернет объект None .
Пример возвращения значений
def absolute_value(num): """ Возвращает абсолютное значение введенного числа""" if num >= 0: return num else: return -num print(absolute_value(2)) print(absolute_value(-4))
Вывод:
Как работают функции
Рассмотрите схему. Так работают функции.
Область видимости и время жизни переменной
Область видимости переменной — это часть программы, в которой к данной переменной можно обращаться. Параметры и переменные, определенные в теле функции, доступны только внутри нее. Это значит, что они находятся в локальной области видимости.
Время жизни переменной — это период, в течение которого переменная находится в памяти. Время жизни переменной внутри функции длится до тех пор, пока функция выполняется. Переменные «уничтожаются», когда мы выходим из функции. Это значит, что функция не помнит значения переменных из предыдущих вызовов.
Вот пример, иллюстрирующий область видимости переменной внутри функции.
def my_func(): x = 10 print("Значение внутри функции:", x) x = 20 my_func() print("Значение вне функции:", x)
Вывод:
Значение внутри функции: 10
Значение вне функции: 20
Здесь мы видим, что значение x изначально равно 20. Хотя функция my_func () изменила значение x на 10, это не повлияло на ее значение вне функции.
Так происходит потому, что локальная переменная x внутри функции отличается от глобальной переменной x , которая находится вне функции. Хотя у них одинаковые имена, это две разные переменные с разной областью видимости.
А вот переменные, которые объявлены вне функции, будут видны внутри нее. У них глобальная область видимости.
Если переменная определена вне функции, то внутри функции мы можем прочитать ее значение. Однако мы не сможем его изменить. Для того, чтобы изменить ее значение, нужно объявить ее как глобальную с помощью ключевого слова global .
Типы функций
Функции в Python можно разделить на два типа:
- Встроенные функции — функции, встроенные в Python.
- Пользовательские функции — функции, созданные пользователями. Чтобы их использовать, нужно устанавливать дополнительные файлы.
СodeСhick.io — простой и эффективный способ изучения программирования.
2023 © ООО «Алгоритмы и практика»
Как использовать функции в Python
Любая функция начинается с инструкции def, названия и набора аргументов в скобках.
Анастасия Хамидулина
Автор статьи
7 июля 2022 в 11:14
В компьютерной терминологии функция — это блок программного кода, который используется несколько раз для решения задачи. Тело функции — набор инструкций, которые поочередно исполняют в процессе вызова.
Обычно у функции есть один или несколько аргументов. Их указывают в скобках во время вызова. Они делятся на обязательные (позиционные) и со значением по ключу (именованные).
Синтаксис функций в Python
Любые функции и методы начинаются с инструкции def (от английского define — «определять»). За def в Python идет название функции, после — набор аргументов. Двоеточие в конце открывает блок тела функции, которое располагают с новой строки.
Изучить все функции и методы можно на курсе Skypro «Python-разработчик». За несколько месяцев реально освоить теорию и навыки, чтобы найти работу по новой специальности. А специалисты центра карьеры помогут составить цепляющее резюме и подготовиться к собеседованию.
В Python нет фигурных скобок для блока кода. Вместо них применяют отступы в четыре пробела. Новая инструкция — новая строка. Или можно отделить их точкой с запятой.Чтобы завершить функцию и вернуть из нее значение, используют ключевое слово return. Если этого не указать, то, когда тело функции достигает конца, функция завершится. Возвращается объект типа None.

Аргументы и их виды
Если надо передавать аргументы через функцию, нужно расположить их в скобках по порядку. Исключение — именованные аргументы. Такие аргументы могут идти в любом порядке, но сначала — позиционные.
Позиционные
Это обязательные аргументы. Чтобы функция работала корректно, важно размещать их в определенном порядке.
def addfunc(val1, val2): return val1 + val2 result = addfunc(3, 2) print(result) 5 addfunc() # вызов без аргументов Traceback (most recent call last): . TypeError: addfunc() missing 2 required positional arguments: 'val1' and 'val2' addfunc(1) # вызов с одним аргументом Traceback (most recent call last): . TypeError: addfunc() missing 1 required positional argument: 'val2'
Когда вызывают функцию addfunc, то передают ей два обязательных аргумента. Они будут доступны внутри тела функции и ассоциированы с переменными val1 и val2. Если этого не сделаете, получите ошибку TypeError.
Но иногда нужны более гибкие функции, которые работают с переменной длиной аргументов. Для этого есть специальная конструкция, она упаковывает переданные позиционные аргументы в переменную:
def addconcat(*args): value = 0 for item in args: if isinstance(item, (int, float)): value += item else: print(f" is not a digit") return value total = addconcat(1, "Hello", 2, 3, 4, "Python", 5.0, 6.25, 7.15, 'string') Hello is not a digit World is not a digit string is not a digit print("Total:", total) Total: 28.4
Обращаются к позиционному аргументу такого множества с помощью операции индексации:
def demo_func(*args): try: print(args[0]) print(args[1]) except IndexError: pass
Python-разработчик: новая работа через 9 месяцев
Получится, даже если у вас нет опыта в IT

Именованные
Это параметры функции с предустановленным значением. Перезаписать его можно с помощью нового значения по имени атрибута:
def hey_concat(*args, name="World!"): print("Hey there,", name) hey_concat() Hey there, World! hey_concat(name="Alex") Hey there, Alex
Атрибуту name присвоили иное значение. Это поменяет результат склеивания строк и последующий вывод.
Именованные аргументы могут быть переменной длины. Конструкция упаковывания параметров похожа на предыдущую, но вместо множества используют словарь:
def print_kwargs(**kwargs): print(kwargs) # отобразит словарь print_kwargs(kone=»One», ktwo=2, kthree=3.0)
Для доступа к значениям именованных аргументов внутри функции используют интерфейс словаря. Вы можете проверить наличие ключа, соответствие значения типу. А еще предусмотреть прочие проверки, прежде чем исполнять тело функции.
def kwargs_addconcat(**kwargs): a = kwargs.get("a", None) b = kwargs.get("b", None) if not isinstance(a, type(b)): raise TypeError("Ошибка! Разные типы") if isinstance(a, str): return f"Результат конкатенации строк\n" elif isinstance(a, int): return f"Результат сложения чисел\n" return "Ошибка" print(kwargs_addconcat(a=1, b=2)) Результат сложения чисел 3 print(kwargs_addconcat(a=1, b="World!")) . TypeError: Ошибка! Разные типы print(kwargs_addconcat(a="Hello, ", b="World!")) Результат конкатенации строк Hello, World! # Без аргументов print(kwargs_addconcat()) Ошибка
В примере упаковываем именованные аргументы в переменную с названием kwargs. Из нее в теле функции по ключам a и b пытаемся получить значения. А если они не найдутся — объект None. Далее проверяем наличие обоих аргументов и принадлежность одному типу данных. Затем возвращаем результат выполнения в зависимости от типа переданных параметров.
Еще можно комбинировать позиционные и именованные параметры. Сначала располагают позиционные (обязательные) аргументы. Сразу за ними идет переменная, в которую записывают все остальные параметры без явного ключа. Далее — именованные аргументы с предустановленным значением (значением по умолчанию). После него располагают переменную словаря с остальными именованными параметрами.
Общая форма последовательности:
def func(a, b, *args, name="Default", **kwargs): return None
Функции и области видимости
Область видимости разрешает конфликт имен и гарантирует, что любой объект, созданный внутри функции, не перезапишет предыдущий объект с таким же именем без явного указания.
✈️ Глобальная
Это пространство имен модуля. В него входят названия переменных, классов, функций и всех остальных объектов, созданных в конкретном файле.
var1 = 12 def global_func(): print(x)
Здесь целочисленный объект var1 и функция global_func — в глобальной области видимости.
✈️ Локальная
Внутри функций можно создавать временные переменные для вычислений. Чтобы избежать конфликта имен и случайной перезаписи, под каждую функцию выделяется свое пространство:
var1 = 2213 # глобальная переменная # глобальная функция, использующая глобальную переменную def func_one(): print(var1) # глобальная функция, использующая локальную переменную def func_two(): var1 = "Local value" # создание локальной переменной print(var1) # функция, изменяющая значение глобальной переменной def func_three(): global var1 var1 = "Local to global"
В последней функции указываем, что хотим использовать глобальную переменную с помощью ключевого слова global вместе с именем нужной переменной.
func_one() 2213 func_two() Local value func_three() # функция меняет значение глобальной переменной func_one() # и результат функции func_one Local to global
✈️ Область объемлющих функций
В Python есть ключевое слово nonlocal. Например, его применяют при создании декораторов. Оно указывает, что нужно использовать переменную уровнем выше, но при этом не относящуюся к глобальной области видимости.
Так реализуют декоратор счетчика вызова функции Python с этим ключевым словом:
def count_deco(wrapper_func): var = 0 def inner(): nonlocal var wrapper_func() var += 1 print(var) return inner @count_deco def deco_demo(): print("A few of example text. ") for _ in range(5): deco_demo() A few of example text. 1 A few of example text. 2 A few of example text. 3 A few of example text. 4 A few of example text. 5
Lambda-функции (анонимные)
Одна из интересных особенностей Python — это анонимные (лямбда) функции. Это простое выражение, которое можно присвоить переменной и использовать повторно. Чаще применяют для фильтрации элементов множества:
list_values = [1, 3, 4, 2, 6, 7, 5, 8, 9] filter(lambda x : x % 2 == 0, list_values) [2, 4, 6, 8]
Оператор возврата return
Результат вычислений функции возвращают с помощью инструкции return. Возвращать можно объекты любого типа и в любом количестве через запятую.
Если функция возвращает несколько объектов, они будут запакованы в кортеж (tuple). Тогда к конкретным элементам обращаются либо по индексу, либо с помощью распаковки множества, где каждый элемент присваивают отдельной переменной. Функция, где явно не указано возвращаемое значение, по умолчанию вернет объект типа None.
def arithmetics(x, y): return x + y, x - y, x * y, x / y, x // y results = arithmetics(22, 3) print(results) (25, 19, 66, 7.333333333333333, 7) print(results[0]) 25 r1, r2, r3, r4, r5 = arithmetics(4, 4) # результаты сложения и умножения print(r1) 8 print(r3) 16
Оператор возврата yield
Помимо обычных есть функции-генераторы. Очевидный плюс — они в оперативной памяти не хранят все объекты, которые используют. Есть отложенное выполнение. Такая функция возобновляет работу там, где остановилась. Она генерирует значения, а не вычисляет их.
Эту функцию используют, чтобы создавать автоматические тесты, что здорово ускоряет и упрощает работу тестировщика. Научиться автоматизации можно на курсе Skypro «Инженер по тестированию». Опытные преподаватели-практики дадут всю необходимую теорию и помогут отработать знания на практических задачах.

QA-автоматизатор. Знакомство с Python. Урок 1
Чтобы передать аргументы генератору и вернуть значения, применяют ключевое слово yield. Когда элементы объекта-генератора заканчиваются, тот возбуждает исключение типа StopIteration:
def gen_demo(times, var): for _ in range(times): yield var gen_inst = gen_demo(25, "Gen demo text") for _ in range(26): print(next(gen_inst)) Gen demo text Gen demo text Gen demo text Gen demo text . Traceback (most recent call last): . StopIteration
[FAQ] Частые вопросы
Функции vs процедуры — в чём отличие?
Процедура — это единичная инструкция, функция — подпрограмма, которая выполняет действие.
Для чего нужна область видимости?
Чтобы решить конфликт имен.
Как провести распаковку множества?
Нужно присвоить его такому же количеству переменных, сколько в нём содержится объектов.
Обязательно ли наличие аргументов для функции?
Нет, но чаще у функции есть один или несколько аргументов.
Основы применения вложенных функций в Python
Распространенный вариант использования внутренних функций – когда нужно защитить или скрыть функцию от всего, что происходит за ее пределами, то есть полностью скрыть функцию из глобальной области видимости. Такое поведение обычно называют инкапсуляцией.
Начнем с поясняющего примера:
def increment(number): def inner_increment(): return number + 1 return inner_increment()
>>> print(increment(10)) 11 # Вызовем вложенную функцию inner_increment() >>> print(inner_increment()) NameError: name 'inner_increment' is not defined
В этом примере у нас нет прямого доступа к inner_increment() . Попытавшись обратиться к вложенной функции, мы получаем NameError . Функция increment() полностью скрывает функцию inner_increment() , предотвращая доступ из глобальной области.
Создание внутренних вспомогательных функций
Иногда нам нужна функция, выполняющая один и тот же фрагмент кода в нескольких местах своего тела. Например, мы хотим написать функцию для обработки файла CSV, содержащего информацию о точках доступа Wi-Fi в Нью-Йорке. Чтобы узнать общее количество точек доступа, а также информацию о компании, которая их предоставляет, мы создали следующий скрипт:
import csv from collections import Counter def process_hotspots(file): def most_common_provider(file_obj): hotspots = [] with file_obj as csv_file: content = csv.DictReader(csv_file) for row in content: hotspots.append(row["Provider"]) counter = Counter(hotspots) print( f"В Нью-Йорке точек Wi-Fi.\n" f" из них предоставляет" f"." ) if isinstance(file, str): # Получаем путь к файлу file_obj = open(file, "r") most_common_provider(file_obj) else: # Забираем объект файла most_common_provider(file)
Здесь process_hotspots() принимает аргумент file и проверяет, является ли файл строковым путем к физическому файлу или файловым объектом. Затем функция вызывает вспомогательную внутреннюю функцию most_common_provider() , которая принимает файловый объект и выполняет следующие операции:
- Считывает содержимое файла в генератор, который создает словари с помощью csv.DictReader .
- Составляет список провайдеров Wi-Fi.
- Подсчитывает количество точек доступа Wi-Fi для каждого поставщика с помощью объекта collections.Counter .
- Печатает сообщение с полученной информацией.
Запустив функцию, мы получим следующий результат:
>>> from hotspots import process_hotspots >>> file_obj = open("./NYC_Wi-Fi_Hotspot_Locations.csv", "r") >>> process_hotspots(file_obj) В Нью-Йорке 3319 точек Wi-Fi. 1868 из них предоставляет LinkNYC - Citybridge. >>> process_hotspots("./NYC_Wi-Fi_Hotspot_Locations.csv") В Нью-Йорке 3319 точек Wi-Fi. 1868 из них предоставляет LinkNYC - Citybridge.
Независимо от того, вызываем ли мы process_hotspots() со строковым путем к файлу или с файловым объектом, вы получите один и тот же результат.
Использование внутренних и приватных вспомогательных функций
Обычно мы создаем вспомогательные внутренние функции, такие как most_common_provider() , когда хотим обеспечить инкапсуляцию либо если не собираемся вызывать их где-либо еще, кроме включающей функции.
Хотя написание внутренних вспомогательных функций дает желаемый результат, обычно лучше вынести их, как функции верхнего уровня. В этом случае можно использовать префикс из знака подчеркивания (_) в имени функции, чтобы указать, что она является приватной для текущего модуля или класса. Это позволит получить доступ к вспомогательным функциям из любого места в текущем модуле или классе и повторно использовать их по мере необходимости.
Извлечение внутренних функций в приватные функции верхнего уровня может сделать код чище и читаемее. Такая практика соответствует принципу единственной ответственности.
Сохранение состояния с помощью вложенных функций: замыкания в Python
Функции Python в своих правах равны любым другим объектам, таким как числа, строки, списки, кортежи, модули и т. д. То есть их можно динамически создавать или уничтожать, сохранять в структурах данных, передавать в качестве аргументов другим функциям, использовать как возвращаемые значения.
В Python также можно создавать функции высшего порядка, которые принимают и возвращают другие функции.
Примеры внутренних функций, которые мы видели до сих пор, были обычными функциями, которые волей случая оказались вложенными внутрь других функций. Если нам не нужно скрывать эти функции от внешнего мира, то и нет особых причин для вложения.
В этом разделе мы поговорим о другом роде вложенных функций – замыканиях. Это динамически создаваемые функции, возвращаемые другими функциями. Главная особенность состоит в том, что замыкания имеют полный доступ к переменным и именам, определенным в локальном пространстве имен, в котором было создано замыкание, даже если включающая функция завершила свое выполнение.
Чтобы определить замыкание, нужно выполнить три шага:
- Создать вложенную функцию.
- Сослаться на переменные из включающей функции.
- Вернуть вложенную функцию.
Сейчас разберемся на примерах.
Сохранение состояния в замыкании
Итак, замыкание заставляет вложенную функцию при вызове сохранять состояние своего окружения. То есть замыкание – это не только сама внутренняя функция, но и окружающая среда.
Рассмотрим следующий пример:
def generate_power(exponent): def power(base): return base ** exponent return power
Здесь мы определяем функцию generate_power() , которая представляет собой фабрику для создания замыканий. То есть эта функция при каждом вызове создает и возвращает новую функцию-замыкание. В следующей строке определяется функция power() , которая является внутренней функцией, и принимает единственный аргумент base и возвращает результат выражения base ** exponent . Последняя строка возвращает power как функциональный объект, не вызывая его.
Откуда power() получает значение показателя степени exponent ? Вот где в игру вступает замыкание. В этом примере power() получает значение экспоненты из внешней функции generate_power() . Вот что делает Python, когда мы вызываем generate_power() :
- Определяет новый экземпляр power() , который принимает аргумент base .
- Делает «снимок» окружения power() . Он включает exponent с текущим значением.
- Возвращает power() вместе с состоянием.
Таким образом, когда мы вызываем экземпляр power() , возвращаемый функцией generate_power() , мы видим, что функция запоминает значение степени exponent :
>>> raise_two = generate_power(2) >>> raise_three = generate_power(3) >>> raise_two(4) 16 >>> raise_two(5) 25 >>> raise_three(4) 64 >>> raise_three(5) 125
Обратите внимание, что оба замыкания запоминают соответствующий показатель степени между вызовами. В этих примерах raise_two() запоминает, что exponent = 2 , а raise_three() запоминает, что exponent = 3 .
Рассмотрим другой пример:
def has_permission(page): def permission(username): if username.lower() == "admin": return f"'' имеет доступ к ." else: return f"'' не имеет доступа к ." return permission check_admin_page_permision = has_permission("Admin Page")
>>> print(check_admin_page_permision("admin")) 'admin' имеет доступ к Admin Page. >>> print(check_admin_page_permision("john")) 'john' не имеет доступа к Admin Page.
Вложенная функция проверяет, имеет ли данный пользователь необходимы права доступа к странице. Вместо того чтобы проверять, равен ли пользователь ‘admin’ , можно сделать запрос к базе данных.
Обычно замыкания не изменяют состояние, которое они получили «при рождении», как было показано в приведенных выше примерах. Но можно создавать и динамические замыкания, используя изменяемые объекты – словари, множества или списки.
Предположим, нужно вычислить среднее значение для набора данных. Данные поступают в виде потока последовательных измерений анализируемого параметра, и нужно, чтобы функция сохраняла между вызовами предшествующие измерения. В этом случае можно код фабрики для создания замыканий может выглядеть следующим образом:
def mean(): sample = [] def inner_mean(number): sample.append(number) return sum(sample) / len(sample) return inner_mean sample_mean = mean()
>>> sample_mean(100) 100.0 >>> sample_mean(105) 102.5 >>> sample_mean(101) 102.0 >>> sample_mean(98) 101.0
Замыкание, присвоенное sample_mean , сохраняет состояние выборки между вызовами. Хотя мы определяем список sample внутри mean() , он также доступен и в замыкании.
Изменение состояния замыкания
Обычно переменные замыкания полностью скрыты от внешнего мира. Однако мы можем задать для них функции геттера и сеттера:
def make_point(x, y): def point(): print(f"Point(, )") def get_x(): return x def get_y(): return y def set_x(value): nonlocal x x = value def set_y(value): nonlocal y y = value # Добавляем геттеры и сеттеры point.get_x = get_x point.set_x = set_x point.get_y = get_y point.set_y = set_y return point point = make_point(1, 2)
>>> point.get_x() 1 >>> point.get_y() 2 >>> point() Point(1, 2) >>> point.set_x(42) >>> point.set_y(7) >>> point() Point(42, 7)
Здесь make_point() возвращает замыкание, представляющее объект point . К этому объекту прикреплены функции, которые мы можем использовать для получения доступа к чтению и записи переменных x и y .
Такая фабрика может работать даже быстрее, чем эквивалентный класс, но подход не предоставляет наследование, дескрипторы и прочие возможности классов Python.
Изменение поведения с помощью вложенных функций: декораторы
Декораторы Python – еще один популярный и удобный вариант использования внутренних функций, особенно для замыканий. Декораторы – это функции высшего порядка, которые принимают в качестве аргумента вызываемый объект (функцию, метод, класс) и возвращают другой вызываемый объект.
Примечание
Если концепция декораторов вызывает у вас трудности, обратите внимание на нашу публикацию Всё, что нужно знать о декораторах Python.
Обычно декораторы применяются для динамического добавления свойств к существующему вызываемому объекту и прозрачного расширения его поведения, не затрагивая и не изменяя вызываемого объекта. Функцию-декоратор можно применить к любому вызываемому объекту. Для этого в предваряющей его строке ставится символ @ и имя декоратора:
@decorator def decorated_func(): # Function body. pass
Этот синтаксис заставляет decorator() автоматически принимать decorator_func() в качестве аргумента и обрабатывать его в своем теле. Эта операция является сокращением для инструкции следующего вида:
decorated_func = decorator(decorated_func)
Вот пример того, как можно создать функцию-декоратор для изменения поведения уже существующей функции:
def add_messages(func): def _add_messages(): print("Это мой первый декоратор.") func() print("Пока!") return _add_messages @add_messages def greet(): print("Привет, мир!") greet()
Это мой первый декоратор. Привет, мир! Пока!
В этом примере мы используем @add_messages для декорирования функции greet() . В результате функция приобретает новые функциональные возможности. Теперь, когда мы вызываем greet() , вместо того, чтобы просто напечатать Привет, мир! , она выводит два дополнительных сообщения.
Простейшей практикой отладки кода на Python является вставка вызовов print() для проверки значений переменных. Однако, добавляя и удаляя вызовы print() , мы рискуем забыть о некоторых из них. Чтобы предотвратить эту ситуацию, мы можем написать следующий декоратор:
def debug(func): def _debug(*args, **kwargs): result = func(*args, **kwargs) print( f"(args: , kwargs: ) -> " ) return result return _debug @debug def add(a, b): return a + b
>>> add(5, 6) add(args: (5, 6), kwargs: <>) -> 11 11
В этом примере функция-декоратор debug () печатает имя декорируемой функции, текущие значения каждого аргумента и возвращаемый результат. Такой декоратор можно использовать для простейшей отладки функций. Как только мы получаем желаемый результат, достаточно удалить вызов декоратора @debug , и отлаженная функция будет работать как обычно.
Приведем последний пример и заново реализуем generate_power() в виде функции-декоратора:
def generate_power(exponent): def power(func): def inner_power(*args): base = func(*args) return base ** exponent return inner_power return power @generate_power(2) def raise_two(n): return n @generate_power(3) def raise_three(n): return n
>>> raise_two(7) 49 >>> raise_three(5) 125
Эта версия generate_power() дает те же результаты, что и в исходной реализации. В этом случае мы используем для запоминания показателя степени и замыкание, и декоратор, который возвращает измененную версию функции func() .
Здесь декоратор должен принимать аргумент (показатель степени), поэтому нам потребовалось два уровня вложенность. Первый уровень представлен функцией power() , которая принимает в качестве аргумента декорируемую функцию. Второй уровень представлен функцией inner_power() , которая упаковывает показатель степени в args , выполняет окончательный расчет и возвращает результат.
Заключение
Итак, в Python вложенные функции имеют прямой доступ к переменным и именам, которые вы определяете во включающей функции. Это предоставляет механизм для инкапсуляции функций, создания вспомогательных решений, реализации замыканий и декораторов.
