Ключове слово def у Python перетворює хаос коду на елегантні блоки, які можна викликати коли завгодно, ніби викликаючи вірного слугу. Це не просто синтаксис – це фундамент програмування, де проста функція може обчислювати факторіал чи керувати асинхронними запитами до сервера. Уявіть: замість копіювати рядки print по сто разів, ви пишете def greet(name): print(f”Привіт, {name}!”) – і готово, код чистий, як свіжий сніг.
Функція, створена через def, приймає параметри, виконує логіку і повертає результат через return, або мовчки завершується з None. Ось базовий приклад: def suma(a, b): return a + b. Викликаєте suma(5, 3) – отримуєте 8. Просто, потужне і незамінне для будь-якого скрипта, від автоматизації офісних завдань до машинного навчання.
Але def ховає набагато більше: від змінної кількості аргументів до декораторів, що додають логування одним рядком. Ця стаття розбере все по кісточках, з прикладами, які копіюйте і тестуйте прямо в інтерпретаторі.
Що ховається за def: суть функцій у Python
Def означає “define” – визначити. Воно запускає створення нової функції, яка стає об’єктом першого класу: її можна передавати в аргументах, повертати з інших функцій чи зберігати в словнику. Функції роблять код модульним, повторно використовуваним і легким для тестування. Без них Python перетворився б на спагеті з копіпастом.
Кожна функція має своє простір імен – локальну область видимості. Змінні всередині def живуть тільки там, доки функція виконується. Це захищає від конфліктів, ніби кожна кімната в будинку має свої шафи. А правило LEGB (Local, Enclosing, Global, Built-in) визначає, де шукати змінну: спочатку локально, потім у зовнішніх функціях, глобально чи вбудовано.
Згідно з офіційною документацією Python (docs.python.org), def створює символічну таблицю для локальних змінних при кожному виклику. Це гарантує ізоляцію, але вимагає уваги до global чи nonlocal для змін зовнішніх даних.
Синтаксис def: як правильно створювати функції
Базовий шаблон простий: def назва(параметри): з відступом йде тіло. Назва – snake_case, бо Python любить нижній регістр з підкресленнями. Параметри в дужках опціональні, двокрапка обов’язкова, тіло – з відступом у 4 пробіли.
Додайте докстринг – рядок у потрійних лапках на початку тіла. Він стає __doc__ атрибутом функції, корисним для help(функція) чи автодокументації. Ось приклад:
def calculate_area(radius: float) -> float:
"""
Обчислює площу кола за формулою πr².
Args:
radius: Радіус кола (позитивне число).
Returns:
Площа кола.
"""
import math
return math.pi * radius ** 2
Тепер help(calculate_area) видасть гарний опис. Докстринги – не примха, а стандарт PEP 257 для професійного коду.
- Напишіть def з назвою, що описує дію: не func1, а process_user_data.
- Додайте параметри після двокрапки.
- Тіло з відступом: логіка, return якщо потрібно.
- Тестуйте викликом: result = calculate_area(5); print(result).
Цей ритуал робить код самодокументованим. А тепер уявіть масштаби: тисячі функцій у проекті, і все чітко, бо синтаксис на висоті.
Параметри функцій: від базових до *args і **kwargs
Параметри – це двері для даних у функцію. Позиційні передаються по порядку, ключові – як ключ=значення. За замовчуванням параметри позиційні, але з 3.8 додано / для тільки-позиційних і * для тільки-ключових.
Значення за замовчуванням економлять зусилля: def greet(name=”Гість”): print(f”Привіт, {name}!”). Викликайте greet() – “Привіт, Гість!”. Але обережно з мутабельними: def bad_func(lst=[]): lst.append(1); return lst. Кожен виклик додає до одного списку! Фікс: lst=None, if not lst: lst=[].
Змінна кількість: *args збирає позиційні в tuple, **kwargs – ключові в dict. Ідеально для гнучких API.
def universal_sum(*args, separator=', '):
return separator.join(map(str, args))
print(universal_sum(1, 2, 3)) # 1, 2, 3
def info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
info(name="Олена", age=28)
Комбінуйте: def full_example(a, b=0, *args, mode=’auto’, **kwargs): …. Тут a/b позиційні, args – зайві позиційні, mode/kwargs – ключові.
| Тип параметра | Синтаксис | Приклад виклику | Результат |
|---|---|---|---|
| Позиційний | a | func(10) | a=10 |
| За замовчуванням | b=5 | func(10) або func(10,20) | b=5 або b=20 |
| *args | *numbers | func(1,2,3) | numbers=(1,2,3) |
| **kwargs | **data | func(x=1,y=2) | data={‘x’:1,’y’:2} |
| Тільки позиційний (/) | a / | func(10) | Помилка при func(a=10) |
| Тільки ключовий (*) | * , k=1 | func(k=10) | Помилка при func(10) |
Джерела даних: документація Python (docs.python.org). Така таблиця допомагає швидко орієнтуватися, бо параметри – ключ до гнучкості. У реальних проектах *args/**kwargs роблять функції універсальними, як швейцарський ніж.
Return: як функції повертають скарби
Без return функція повертає None, мовчки завершуючи роботу. Але з return value – це ваш трофей. Може повертати числа, списки, dict чи навіть функції! def power(base, exp): return base ** exp. Готово, reusable математика.
Ранні return економлять код: def is_even(n): if n % 2: return False; return True. Коротко і ясно. А множинні return? Python дозволяє, бо функція завершується на першому.
Важливо: return з tuple розпаковується автоматично в присвоєнні: a, b = divmod(10,3). Це магія для множинних значень.
Область видимості: local, global, nonlocal у дії
Локальні змінні народжуються в def і гинуть після. Зовнішні бачаться для читання, але зміна створює локальну копію. Хочете міняти глобальну? global x. Для вкладених – nonlocal x.
- Local: x = 5 всередині def – окрема.
- Enclosing: у outer def y=10; inner бачить y.
- Global: global z міняє модульну.
- Built-in: print, len – завжди доступні.
Приклад замикання (closure): def multiplier(factor): def inner(n): return n * factor; return inner. mult2 = multiplier(2); mult2(5) == 10. Factor “запам’ятовується”!
Ці нюанси рятують від багів, роблячи код передбачуваним.
Вкладені функції та замикання: функції, що пам’ятають
Def всередині def – вкладена функція. Вона бачить зовнішні змінні, створюючи closure. Корисно для фабрик: def create_adder(x): def adder(y): return x + y; return adder.
З nonlocal міняйте зовнішні: def counter(): count = 0; def increment(): nonlocal count; count +=1; return count; return increment. Кожен виклик збільшує!
Замикання – основа декораторів і callback’ів. Ви не повірите, наскільки це потужне для станних функцій без класів.
Декоратори: @ над def для суперсил
Декоратор – функція, що обгортає іншу, додаючи фічі. Синтаксис: @timer def slow_func(): …. Де timer – def, що повертає wrapper.
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__} took {time.time()-start:.2f}s")
return result
return wrapper
@timer
def factorial(n):
return 1 if n == 0 else n * factorial(n-1)
factorial(100)
Результат: час рекурсії! functools.wraps зберігає метадані. Декоратори – для логів, кешу (lru_cache), авторизації. З Python 3.9 @ з assignment_expression.
Практичні кейси: def у реальному житті
Кейс 1: Веб-скрапінг. def fetch_data(url): import requests; return requests.get(url).text. З декоратором retry для помилок мережі.
Кейс 2: Data science. def preprocess(df, columns): for col in columns: df[col] = df[col].fillna(0); return df. З *columns для гнучкості.
Кейс 3: API сервер (Flask/FastAPI). @app.route(‘/’) def home(): return “Hello!”. Асинхронно: async def api_call(): await asyncio.sleep(1); return data.
Кейс 4: Автоматизація. def backup_files(folder, days=7): shutil.copytree… З **options для формату архіву. Ці приклади економлять години!
Генератори: def з yield для ледачих послідовностей
Замініть return на yield – отримайте генератор. Не список у пам’яті, а ітератор on-demand. def fib_gen(n): a,b=0,1; while a
for num in fib_gen(1000): print(num). Економить пам’ять для гігантських даних. next(gen) – наступний елемент. Send(), throw() для інтерактивності.
Генератори – must-have для потоків даних, як у pandas чи ML датасетах.
Async def: асинхронність для швидкості
Async def створює coroutine. Використовуйте await для IO: async def fetch(url): async with aiohttp.ClientSession() as session: async with session.get(url) as resp: return await resp.text(). asyncio.run(fetch(‘site.com’)).
Ідеально для серверів, API, де очікування – ворог. З Python 3.5+ стандарт, у 3.13 кращі typing для async.
Аннотації типів: робимо def типобезпечним
def add(a: int, b: int) -> int: return a+b. Mypy перевірить! typing.List[str], Union[int,float]. З 3.12 type params [T], 3.13 defaults.
Не впливає на runtime, але IDE підкаже помилки. Типи – місток до enterprise-коду.
Lambda: короткі def без імені
Lambda args: expression. sorted(items, key=lambda x: x.age). Швидко для map/filter. Обмежено одним виразом, але блискавично.
Комбінуйте з functools.partial для часткового застосування.
Типові помилки та як їх уникати
1. Mutable defaults – фікс з None. 2. Забули return – None surprise. 3. Scope баги без nonlocal. 4. Рекурсія без бази – стек overflow. Тестуйте з pytest!
Функції з def – ваш арсенал. Експериментуйте, будуйте проекти, і Python розкриється повністю.