Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 2 из 20 Начальный 15 мин 100 XP

Аргументы функции в 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('Хлеб')
Python ответит TypeError: print_price() missing 1 required positional argument: 'price'. Параметр price обязателен — значения по умолчанию появятся в уроке про умолчания.
ошибка: лишний аргумент
# Так не запускается: третьему значению нет места
def print_price(item, price):
    print(f'{item}: {price} руб.')

print_price('Хлеб', 45, 'батон')
Python ответит TypeError: print_price() takes 2 positional arguments but 3 were given. Параметров два — аргументов тоже должно быть два.

Порядок аргументов = порядок параметров

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 объявлена один раз, а тело цикла вызывает её для каждой пары из словаря. Правка формата строки — в одном месте, в теле функции: цикл остаётся коротким, а печать — переиспользуемой.

ТерминГде живётПример
ПараметрВ объявлении, в скобках после defdef 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 не копирует аргументы, он передаёт ссылку на тот же объект. Функция дописала элемент — и корзина в вызывающем коде стала длиннее на один.

append меняет список вызывающего кода
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)
Проверь себя
0 / 9

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 пришёл аргументом. Что будет с исходным списком?

Карточки терминов
Запомнено: 0 / 8
Практика

Напиши функцию show_gift(name, gift), которая печатает строку вида «Аня получает чайник». Вызови её дважды: для Ани с чайником и для Бориса с пледом.

practice.py
Вопросы и ответы по уроку

Как передать данные в функцию в 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-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.