Функции в Python — полный гайд для аналитика
Коротко
Функция в Python — блок кода, который можно вызвать по имени сколько угодно раз. Объявляется через def, принимает аргументы, возвращает результат через return. Для аналитика функции — способ не дублировать код: вычисление метрики, очистка данных, пакетная обработка файлов. На собеседованиях спрашивают про типы аргументов, область видимости и подводные камни с мутабельными значениями по умолчанию.
Синтаксис def и return
def calc_conversion(visitors, buyers):
"""Считает конверсию."""
if visitors == 0:
return 0.0
return buyers / visitors
rate = calc_conversion(1000, 32)
print(rate) # 0.032def создаёт функцию с именем. return возвращает значение — без него функция вернёт None. Строка в тройных кавычках сразу после def — docstring. Она не влияет на выполнение, но видна через help(calc_conversion).
Возврат нескольких значений
Python позволяет вернуть несколько значений через кортеж:
def describe_metric(values):
total = sum(values)
avg = total / len(values)
return total, avg
total, avg = describe_metric([100, 200, 150])
print(total) # 450
print(avg) # 150.0Технически return total, avg возвращает кортеж (450, 150.0). Распаковка через total, avg = ... — стандартный паттерн.
Аргументы по умолчанию
def format_metric(value, decimals=2, suffix='%'):
return f"{value:.{decimals}f}{suffix}"
format_metric(0.156) # '0.16%'
format_metric(0.156, 1) # '0.2%'
format_metric(1500, 0, ' ₽') # '1500 ₽'Аргументы со значением по умолчанию идут после обязательных. При вызове их можно опустить — подставится дефолт.
Позиционные и именованные аргументы
Аргументы можно передавать по позиции или по имени (keyword):
def retention(cohort_size, retained, period='d7'):
rate = retained / cohort_size
return f"{period}: {rate:.1%}"
# Позиционные
retention(500, 120) # 'd7: 24.0%'
# Именованные — порядок не важен
retention(retained=120, cohort_size=500, period='d30')Именованные аргументы делают вызов понятнее — особенно когда параметров много.
*args и **kwargs
*args собирает лишние позиционные аргументы в кортеж, **kwargs — именованные в словарь.
def log_event(event_name, *properties, **options):
print(f"Event: {event_name}")
print(f"Properties: {properties}")
print(f"Options: {options}")
log_event('purchase', 'premium', 'annual', user_id=42, source='bot')
# Event: purchase
# Properties: ('premium', 'annual')
# Options: {'user_id': 42, 'source': 'bot'}На практике аналитик чаще встречает **kwargs при написании обёрток — например, функция, которая прокидывает параметры в pd.read_csv():
def load_csv(path, **kwargs):
df = pd.read_csv(path, **kwargs)
df.columns = df.columns.str.strip().str.lower()
return df
df = load_csv('data.csv', sep=';', encoding='cp1251')Область видимости: local vs global
Переменные внутри функции — локальные. Они не видны снаружи:
x = 10 # глобальная
def foo():
x = 20 # локальная — другая переменная
print(x)
foo() # 20
print(x) # 10 — глобальная не измениласьЧтобы изменить глобальную из функции, нужно global x — но это антипаттерн. Функция должна получать данные через аргументы и возвращать результат через return.
lambda vs def
lambda — анонимная функция из одного выражения. def — полноценная функция с именем, docstring и несколькими строками.
# lambda — для одноразовых колбэков
sorted(data, key=lambda x: x['date'])
# def — для всего остального
def clean_phone(phone):
"""Удаляет пробелы и дефисы из номера."""
return phone.replace(' ', '').replace('-', '')Правило: если функция нужна один раз как аргумент — lambda. Если нужно имя, повторное использование или больше одной строки — def.
Практические примеры для аналитика
Расчёт метрики с защитой от деления на ноль
def safe_ratio(numerator, denominator, default=0.0):
if denominator == 0:
return default
return numerator / denominator
cr = safe_ratio(buyers, visitors)
arpu = safe_ratio(revenue, users)Очистка данных
def clean_column(series):
"""Приводит строковый столбец к нижнему регистру и убирает пробелы."""
return series.str.strip().str.lower()
df['city'] = clean_column(df['city'])
df['category'] = clean_column(df['category'])Пакетная обработка файлов
import glob
import pandas as pd
def load_and_concat(pattern, **read_kwargs):
"""Загружает все CSV по шаблону и склеивает в один DataFrame."""
files = glob.glob(pattern)
frames = [pd.read_csv(f, **read_kwargs) for f in files]
return pd.concat(frames, ignore_index=True)
df = load_and_concat('data/2026-*.csv', sep=';')Частые ошибки
Мутабельный аргумент по умолчанию. Классическая ловушка — список или словарь в значении по умолчанию:
# Баг — список создаётся один раз и переиспользуется
def add_item(item, items=[]):
items.append(item)
return items
add_item('a') # ['a']
add_item('b') # ['a', 'b'] — сюрприз!
# Исправление — None как дефолт
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return itemsДефолтное значение вычисляется один раз при определении функции. Мутабельные объекты (list, dict, set) в дефолтах — почти всегда баг.
Забытый return. Если функция ничего не возвращает явно, результат — None:
def calc_tax(amount):
tax = amount * 0.13
# забыли return tax
result = calc_tax(100000)
print(result) # NoneВопросы с собеседований
— Что вернёт функция без return?
— None. В Python любая функция возвращает значение. Если return отсутствует или написан без выражения (return), функция вернёт None.
— **Что такое *args и kwargs?
— *args собирает позиционные аргументы в кортеж, **kwargs — именованные в словарь. Порядок в сигнатуре: обычные параметры, *args, именованные, **kwargs.
— Чем опасен мутабельный аргумент по умолчанию?
— Дефолт вычисляется один раз при определении функции. Если это список или словарь, он разделяется между всеми вызовами. Стандартное решение — None как дефолт и создание нового объекта внутри функции.
— Чем lambda отличается от def? — lambda — одно выражение, без имени, без docstring. def — полноценная функция. Подробно — в гайде по lambda.
— Что такое docstring и зачем он нужен?
— Строковый литерал сразу после def. Доступен через help() и func.__doc__. Документирует, что делает функция, какие параметры принимает и что возвращает.
Потренировать Python-вопросы на практике можно в тренажёре Карьерника. А больше примеров вопросов — на отдельной странице. Разобраться с типами данных поможет гайд по типам данных, а с обработкой ошибок — гайд по try/except.
Открыть тренажёр в Telegram — вопросы по Python, pandas, SQL и аналитике. Бесплатно.
FAQ
Сколько аргументов может быть у функции в Python?
Формально ограничения нет — но CPython позволяет до 255 позиционных аргументов в вызове. На практике, если параметров больше 5-6, стоит передавать словарь или dataclass.
Можно ли вернуть из функции несколько значений?
Да. return a, b, c возвращает кортеж (a, b, c). При вызове значения распаковываются: x, y, z = func(). Это стандартный подход в Python.
Когда использовать функцию, а когда класс?
Если логика — чистое преобразование данных (вход → выход), достаточно функции. Класс нужен, когда есть состояние, которое меняется между вызовами. Для аналитических скриптов функций обычно хватает.