Аргументы функции в Python: данные внутрь
Функция принимает данные через параметры: greet('Анна') здоровается с Анной. Разбираем позиционные аргументы, порядок и количество — и типичную ошибку TypeError.
Редакция Питоники
Функция из первого урока делала одно и то же: print_line каждый раз рисовала одну и ту же линию. Полезная функция работает с разными данными: одно приветствие — для Анны, Бориса и Веры, одна печать цены — для хлеба и молока. Данные попадают внутрь функции через аргументы — это следующий шаг после def.
Аргументы и параметры: коротко
Параметр — имя в скобках объявления, аргумент — значение в скобках вызова. Позиционные аргументы попадают в параметры по порядку: первый — в первый, второй — во второй. Сколько параметров объявлено, столько аргументов и нужно передать, иначе Python ответит TypeError.
Параметр: переменная в объявлении
Добавим скобкам функции имя-переменную — параметр:
def greet(name):
print(f'Привет, {name}!')
greet('Анна')
greet('Борис')
Привет, Анна! Привет, Борис!
Разбираем по частям. В объявлении def greet(name): — name это параметр: переменная, придуманная вами, как переменная цикла. В вызове greet('Анна') — строка 'Анна' это аргумент: конкретное значение, которое функция получает при вызове. Параметр — это имя в объявлении функции, а аргумент — конкретное значение, которое функция получает при вызове. На первом вызове внутри тела name равно 'Анна', на втором — 'Борис'. Тело написано один раз, а работает с любыми данными.
Сколько параметров — столько аргументов
Параметров может быть несколько — они перечисляются в скобках через запятую:
def print_price(item, price):
print(f'{item}: {price} руб.')
print_price('Хлеб', 45)
print_price('Молоко', 80)
Хлеб: 45 руб. Молоко: 80 руб.
При вызове значения расходуются по позиции: 'Хлеб' попадает в item, 45 — в price. Такие аргументы называют позиционными: важен не только сам аргумент, но и его место в вызове. Параметров не ограничено два — добавьте третий, четвёртый, сколько нужно данным:
def show_card(title, author, year):
print(f'«{title}», {author}, {year}')
show_card('Муму', 'Тургенев', 1852)
show_card('Война и мир', 'Толстой', 1869)
«Муму», Тургенев, 1852 «Война и мир», Толстой, 1869
Правило жёсткое: сколько параметров в объявлении — столько аргументов в вызове. Меньше — Python не сможет заполнить параметр, больше — ему некуда деть лишнее. Обе ситуации дают ошибку:
# Так не запускается: price остался без значения
def print_price(item, price):
print(f'{item}: {price} руб.')
print_price('Хлеб')
# Так не запускается: третьему значению нет места
def print_price(item, price):
print(f'{item}: {price} руб.')
print_price('Хлеб', 45, 'батон')
Порядок аргументов = порядок параметров
Python раскладывает позиционные аргументы по параметрам строго по порядку. Переставьте значения — функция честно их примет, но смысл перепутается:
def show(date, event):
print(f'{date}: {event}')
show('12 июня', 'финал')
show('финал', '12 июня')
12 июня: финал финал: 12 июня
Оба вызова прошли без ошибок: типы подходящие. Но вторая строка вывода бессмысленна — дата и событие поменялись местами. Перепутанный порядок — коварная ошибка: Python её не заметит, если типы совпадают. Спасение — именованные вызовы, им посвящён урок про умолчания и именованные аргументы.
Аргументом может быть что угодно
В скобках вызова можно передать не только строку-константу: подойдёт переменная или выражение — Python вычислит его и передаст в функцию готовый результат:
def shout(word):
print(word.upper() + '!')
word = 'готово'
shout(word)
shout('давай' + '-' + 'вперед')
shout('го')
ГОТОВО! ДАВАЙ-ВПЕРЕД! ГО!
Перед вторым вызовом Python склеил 'давай' + '-' + 'вперед' в одну строку и передал в функцию уже готовый результат. Внутри тела аргумент — обычная переменная: к ней применимы все привычные операции строк.
Функция и цикл: переменная как аргумент
Свяжем это с прошлым разделом: в цикле переменная на каждом шаге получает новое значение — её и передаём в функцию:
def line(name, mark):
print(f'{name}: {mark}')
grades = {'Анна': 5, 'Борис': 4, 'Вера': 3}
for name, mark in grades.items():
line(name, mark)
Анна: 5 Борис: 4 Вера: 3
Функция line объявлена один раз, а тело цикла вызывает её для каждой пары из словаря. Правка формата строки — в одном месте, в теле функции: цикл остаётся коротким, а печать — переиспользуемой.
| Термин | Где живёт | Пример |
|---|---|---|
| Параметр | В объявлении, в скобках после def | def greet(name): — name |
| Аргумент | В вызове, в скобках после имени | greet('Анна') — 'Анна' |
| Позиционный аргумент | Расходуется по порядку вызова | print_price('Хлеб', 45) |
| TypeError | Число аргументов не совпало | print_price('Хлеб') — не хватает price |
Типы аргументов Python не проверяет
Объявление функции — это обещание, а не контракт. Написали print_price(item, price), решили, что price — число в рублях, — и Python молча поверит. Никакой проверки типов при вызове нет: если вместо числа передали строку, функция получит строку и будет работать с ней как умеет. В проекте с чеками это выглядело так: сумма удваивалась для скидки, и вместо 160 печаталось 160160 — нашёлся один переданный по сети аргумент типа строка.
def print_price(item, price):
total = price * 2
print(f'{item}: {total} руб.')
print_price('Хлеб', 45)
print_price('Молоко', '80')
Хлеб: 90 руб. Молоко: 8080 руб.
Строку можно умножать на число — получится та же строка, повторённая дважды. Python не считает это ошибкой, потому что операция для строки осмысленная. Отсюда неприятный вывод: если данные приходят извне (файл, форма, сеть), приводите их к нужному типу сами, на границе входа, а не внутри расчёта. Для чисел это int(value) или float(value), для списков — list(value). Подробнее о типах — урок про аннотации.
Один параметр или список
Когда данные приходят поштучно, нужен параметр на каждое. Когда их много и они однотипные — один параметр-список. Смешивать эти два подхода не стоит: функция с тремя параметрами, где третий — список из трёх элементов, читается хуже, чем просто список.
def print_total(name, items):
total = 0
for item in items:
total = total + item
print(f'{name}: {total} руб.')
print_total('Корзина 1', [120, 80, 45])
print_total('Корзина 2', [30, 15])
Корзина 1: 245 руб. Корзина 2: 45 руб.
| Что приходит в функцию | Как объявить | Пример |
|---|---|---|
| Одно значение | один параметр | show_gift(name, gift) |
| Много однотипных | параметр-список | print_total(name, items) |
| Три разных поля | три параметра | make_order(name, city, comment) |
| Полей много, состав меняется | словарь-параметр | **kwargs — см. урок 11 |
Мы держимся правила: пока полей три и они не меняются — отдельные параметры, читать вызов в глаза приятно. Как только поля начинают прибывать и уезжать (а это происходит с каждым новым требованием заказчика), переходим на словарь — как принимать такие данные, разбирается в уроке про **kwargs.
Список-аргумент меняется в теле функции
Ещё одна ловушка, на которой мы однажды потеряли полчаса. Если в функцию передать список и внутри сделать append, список изменится и у вызывающего кода: Python не копирует аргументы, он передаёт ссылку на тот же объект. Функция дописала элемент — и корзина в вызывающем коде стала длиннее на один.
def add_promo(prices):
prices.append(0)
print('внутри:', len(prices))
cart = [120, 80]
add_promo(cart)
print('снаружи:', len(cart))
внутри: 3 снаружи: 3
| Что пошло не так | Что скажет Python | Что делать |
|---|---|---|
| Аргумент забыли | TypeError: missing 1 required positional argument | Добавьте значение или задайте умолчание |
| Аргумент лишний | TypeError: takes 2 positional arguments but 3 were given | Уберите значение или добавьте параметр |
| Порядок перепутан | Ничего — ошибки нет | Именованные аргументы: print_price(price=45, item='Хлеб') |
| Строка вместо числа | Ничего — ошибки нет | Приводите тип на входе: int(value) |
| Список изменили в функции | Ничего — ошибки нет | Копия: items = list(items) |
Практика: чек по списку позиций
Соберём вместе то, что разобрали: функция получает данные, а цикл подставляет их по одному. Ниже — печать чека: функция одна, вызовов сколько угодно.
def print_line(item, price):
print(f'- {item}: {price} руб.')
cart = [('Хлеб', 45), ('Молоко', 80), ('Сыр', 240)]
for item, price in cart:
print_line(item, price)
- Хлеб: 45 руб. - Молоко: 80 руб. - Сыр: 240 руб.
Функция объявлена один раз, а строки печатает цикл. Поменять формат — значит править одну строку в теле функции, а не весь цикл. Осталось посчитать итог, и тут выясняется, что печатать недостаточно: функции нужно вернуть число, чтобы его можно было сложить и положить в переменную. Это и есть следующий урок.
Функция научилась принимать данные. Осталось научить её отдавать результат наружу: печать видит только человек, а программе нужно значение — положить в переменную, сложить с другим, передать дальше. Как возвращать результат — тема урока про return, а повторять функции по списку вы уже умеете через цикл for.
Сначала предскажи ответ в голове — это главный навык программиста.
def rep(word, n):
print(word * n)
rep('ля', 3)
def f(a, b):
print(a - b)
f(10, 3)
f(3, 10)
def shout(word):
print(word + '!')
name = 'Мяу'
shout(name)
1. Что такое параметр функции?
2. Что такое аргумент?
3. Функция объявлена как def greet(name):. Что произойдёт при вызове greet('Анна', 'Борис')?
4. Как позиционные аргументы попадают в параметры?
5. Функция объявлена как def f(a, b): print(a + b). Что напечатает вызов f(2, 3)?
6. Что можно передать аргументом при вызове?
7. Функция def double(price): print(price * 2). Что напечатает double('80')?
8. Почему Python не ругается, если в функцию передали строку вместо числа?
9. Функция делает prices.append(0), а список prices пришёл аргументом. Что будет с исходным списком?
Напиши функцию show_gift(name, gift), которая печатает строку вида «Аня получает чайник». Вызови её дважды: для Ани с чайником и для Бориса с пледом.
Как передать данные в функцию в Python?
Через параметры и аргументы: в объявлении перечислите параметры — def show(date, event):, при вызове передайте значения — show('12 июня', 'финал'). Позиционные аргументы попадают в параметры по порядку.
Урок 1: первая функция defСколько аргументов можно передать функции?
Ровно столько, сколько параметров объявлено: не хватает или есть лишние — Python ответит TypeError. Как принимать переменное число аргументов, разбирается в уроке про *args.
Урок 10: *argsЧем параметр отличается от аргумента?
Параметр — имя в объявлении (def greet(name):), аргумент — значение в вызове (greet('Анна')). Одна и та же функция при разных вызовах получает разные аргументы, но параметр у неё всегда один — name.
Что будет, если перепутать порядок аргументов?
Если типы подходят, ошибки не будет — функция примет значения и выдаст перепутанный результат: тихая логическая ошибка. Проверяйте порядок при вызове или используйте именованные аргументы: show(event='финал', date='12 июня').
Можно ли передать в функцию любой тип данных?
Да, и это одновременно плюс и минус. Python не сверяет типы аргументов с ожидаемыми: строка вместо числа пройдёт молча и сломает расчёт дальше. Если данные приходят извне — из файла, формы, сети, — приводите их к нужному типу на входе: int(value), float(value), list(value).
Почему при вызове функции возникает TypeError, хотя код написан правильно?
Потому что число аргументов не совпало с числом параметров. Текст ошибки прямо говорит, в чём дело: missing 1 required positional argument — не хватает значения, takes 2 positional arguments but 3 were given — лишнее значение. Сколько параметров объявлено, столько аргументов и передавайте.
Функция изменила переданный ей список. Почему список изменился и снаружи?
Python передаёт ссылку на тот же объект, а не копию: append внутри функции меняет исходный список, и вызывающий код видит это. Если функция должна только читать данные, работайте с копией: items = list(items).
Как правильно объявить функцию, которая принимает много однотипных значений?
Одним параметром-списком: def print_total(name, items). Список значений по очереди разбирается циклом внутри функции. А вот три разных поля заказа — это три отдельных параметра: make_order(name, city, comment). Смешивать виды не стоит.
Понравился урок? Сошлитесь на него
«Параметр — это имя в объявлении функции, а аргумент — конкретное значение, которое функция получает при вызове.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Функции · Урок 1
Функции в Python: первая def
Первая функция: задаём блоку кода имя через def и вызываем по скобкам. Разбираем объявление на части — имя, двоеточие, тело с отступом — и видим, зачем функция вместо копипасты.
Функции · Урок 3
Return в Python: функция возвращает результат
print показывает значение человеку, return отдаёт программе. Учимся возвращать результат, класть его в переменную и использовать в выражениях — и не путать return с print.
Функции · Урок 4
Умолчания и именованные аргументы в Python
Необязательные параметры с запасными значениями и вызов по имени: def f(x, n=2) и f(x=5, n=3). Разбираем порядок параметров и знакомимся с ловушкой изменяемого умолчания.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
ООП · Урок 17
Декораторы: функции над функциями
Декоратор — функция, которая принимает функцию и возвращает новую, добавляя поведение без правки исходного кода. Соберём декоратор с нуля: от замыкания и синтаксиса @ до functools.wraps, декораторов для методов и декораторов с параметрами.
декоратор с параметрами pythonфункция как аргумент python
requests · Урок 2
Параметры GET-запроса: params и query string в requests
Query string глазами Python: словарь params превращается в ?city=Moscow&days=3, русские буквы — в проценты, а parse_qs разворачивает всё обратно. Каждый шаг исполняется на странице.
параметры get запроса pythonquery параметры запроса
Функции · Урок 13
Функция как значение в Python: передача функций
map и sorted уже принимали функции в аргументах — теперь разберём приём целиком: функция такое же значение, как число или строка.
python функция как аргументфункции высшего порядка python