Визначення функцій

Оновлено: 24.04.2023

Визначення функції визначає об’єкт функції, визначений користувачем (див. розділ Стандартна ієрархія типів):

funcdef                   ::=  [decorators] "def" funcname "(" [parameter_list] ")"
                               ["->" expression] ":" suite
decorators                ::=  decorator+
decorator                 ::=  "@" assignment_expression NEWLINE
parameter_list            ::=  defparameter ("," defparameter)* "," "/" ["," [parameter_list_no_posonly]]
                                 | parameter_list_no_posonly
parameter_list_no_posonly ::=  defparameter ("," defparameter)* ["," [parameter_list_starargs]]
                               | parameter_list_starargs
parameter_list_starargs   ::=  "*" [parameter] ("," defparameter)* ["," ["**" parameter [","]]]
                               | "**" parameter [","]
parameter                 ::=  identifier [":" expression]
defparameter              ::=  parameter ["=" expression]
funcname                  ::=  identifier

Визначення функції - це виконуваний оператор. Його виконання прив’язує назву функції в поточному локальному просторі імен до об’єкта функції (обгортка навколо виконуваного коду для функції). Цей об’єкт функції містить посилання на поточний глобальний простір імен як глобальний простір імен, який буде використано під час виклику функції.

Визначення функції не виконує тіло функції; це виконується лише під час виклику функції. 4

Визначення функції може бути обгорнуте одним або кількома виразами decorator. Вирази декоратора обчислюються, коли функція визначена в області видимості, яка містить визначення функції. Результат має бути викликаним, який викликається з об’єктом функції як єдиним аргументом. Повернене значення прив’язується до імені функції замість об’єкта функції. Кілька декораторів застосовуються вкладеним способом. Наприклад, такий код:

@f1(arg)
@f2
def func(): pass

приблизно еквівалентно

def func(): pass
func = f1(arg)(f2(func))

за винятком того, що вихідна функція тимчасово не прив’язана до імені func.

Коли один або більше параметрів мають форму параметр = вираз, кажуть, що функція має «значення параметрів за замовчуванням». Для параметра зі значенням за замовчуванням відповідний argument може бути пропущений у виклику, у цьому випадку значення параметра за замовчуванням замінюється. Якщо параметр має значення за замовчуванням, усі наступні параметри до «*» також повинні мати значення за замовчуванням — це синтаксичне обмеження, яке не виражається граматикою.

Значення параметрів за замовчуванням обчислюються зліва направо, коли виконується визначення функції. Це означає, що вираз обчислюється один раз, коли визначається функція, і що те саме «попередньо обчислене» значення використовується для кожного виклику . Це особливо важливо розуміти, коли значення параметра за замовчуванням є змінним об’єктом, таким як список або словник: якщо функція змінює об’єкт (наприклад, шляхом додавання елемента до списку), значення параметра за замовчуванням фактично змінюється. Загалом це не те, що передбачалося. Щоб обійти це, використайте None за умовчанням і явним чином перевірте його в тілі функції, наприклад:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

Більш детально семантика виклику функції описана в розділі Дзвінки. Виклик функції завжди призначає значення всім параметрам, згаданим у списку параметрів, або з позиційних аргументів, з ключових аргументів, або зі значень за замовчуванням. Якщо присутня форма «*identifier», вона ініціалізується кортежем, що отримує будь-які надлишкові позиційні параметри, за умовчанням порожній кортеж. Якщо присутня форма «*identifier», вона ініціалізується новим упорядкованим відображенням, отримуючи будь-які надлишкові аргументи ключового слова, за умовчанням до нового порожнього відображення того самого типу. Параметри після «*» або «*identifier» є параметрами лише для ключових слів і можуть передаватися лише аргументами ключових слів. Параметри перед «/» є лише позиційними параметрами і можуть передаватися лише позиційними аргументами.

Параметри можуть мати анотацію у формі «:вираз» після імені параметра. Будь-який параметр може мати анотацію, навіть у формі *ідентифікатор або **ідентифікатор. Функції можуть мати анотацію «повернення» у формі «-> вираз» після списку параметрів. Ці анотації можуть бути будь-яким дійсним виразом Python. Наявність анотацій не змінює семантику функції. Значення анотацій доступні як значення словника, ключ якого містить імена параметрів в атрибуті __annotations__ об’єкта функції. Якщо використовується імпорт анотацій із __future__, анотації зберігаються як рядки під час виконання, що дає змогу відкласти оцінку. В іншому випадку вони оцінюються під час виконання визначення функції. У цьому випадку анотації можуть оцінюватися в іншому порядку, ніж у вихідному коді.

Також можна створювати анонімні функції (функції, не прив’язані до імені) для негайного використання у виразах. Тут використовуються лямбда-вирази, описані в розділі Лямбда. Зауважте, що лямбда-вираз — це лише скорочення спрощеного визначення функції; функція, визначена в операторі «def», може бути передана або присвоєна іншому імені так само, як функція, визначена лямбда-виразом. Форма «def» насправді є потужнішою, оскільки вона дозволяє виконувати кілька операторів і анотацій.

Примітка програміста: Функції є об’єктами першого класу. Оператор «def», який виконується всередині визначення функції, визначає локальну функцію, яку можна повертати або передавати. Вільні змінні, які використовуються у вкладеній функції, можуть отримати доступ до локальних змінних функції, що містить def. Перегляньте розділ Називання та зв’язування для деталей.