До этого момента мы вызывали функции в основном с позиционными аргументами. Но в Python функции могут иметь ещё и именованные аргументы (keyword arguments). Что же это такое? Узнаем, взглянув на следующий пример:
def bar(length, char1, char2):
return (char1 + char2) * length + char1
print(bar(5, '-', '*'))
# => -*-*-*-*-*-
Функция bar
имеет три аргумента. Вызов функции тоже выглядит довольно понятно. Теперь предположим, что char1
и char2
чаще всего получают одни и те же значения. В такой ситуации удобно указать значения по умолчанию:
def bar(length, char1='-', char2='*'):
return (char1 + char2) * length + char1
print(bar(5))
# => -*-*-*-*-*-
print(bar(3, '.'))
# => .*.*.*.
print(bar(2, ':', '|'))
# => :|:|:
Выглядит удобно. Но что делать, если нас устраивает значение по умолчанию для char1
, но мы хотим задать своё значение для char2
? Придётся указывать оба? Не придётся, ведь за редким исключением любой позиционный аргумент может быть указан по имени:
print(bar(4, char2='#'))
# => -#-#-#-#-
print(bar(char2='$', length=3))
# => -$-$-$-
Во втором вызове я даже порядок аргументов перепутал и ничего не сломалось! Да, именованные аргументы обладают таким свойством: порядок именованных аргументов не имеет значения!
Однако имеет значение порядок групп аргументов: позиционные значения должны быть указаны до любых именованных! Иначе вы получите ошибку SyntaxError: positional argument follows keyword argument
.
Также в том случае, когда функция имеет позиционные аргументы без значений по умолчанию, значения для этих аргументов обязательно должны быть указаны так или иначе — либо в виде позиционных значений, либо в виде именованных. Нарушение этого правила приведёт к ошибке вида:
bar(char2='!')
# TypeError: bar() missing 1 required positional argument: 'length'
Внимание: нужно различать синтаксис объявления аргументов функции и синтаксис вызова функции. При вызове функции у вас больше свободы. Например, вы можете указывать именованные аргументы перед разворачиваемой группой позиционных:
def f(*args, x=None, y=None):
print('args =', args, ', x =', x, ', y =', y)
f(*(1, 2), x='a', *[3, 4], y='b', *(5, 6))
# => args = (1, 2, 3, 4, 5, 6), x = a, y = b
Каких-то строгих правил на этот счёт не существует. Однако широко практикуется такой подход: если функция принимает больше трёх аргументов, нужно хотя бы часть из них указать по имени. Особенно важно именовать значения аргументов, если несколько значений имеют одинаковый тип. Потому что очень трудно понять, что делает функция с подобным вызовом:
make('circle', 300, 150, 10, None, 2.5, False)
Сравните с этим:
make(
shape='circle',
x=300, y=150, radius=10,
line_pattern=None,
line_width=2.5,
fill=False
)
Такой код читать значительно проще!
Конечно, у вышеупомянутого правила есть пара исключений. Первое: функции, назначение которых очевидно. Да, очевидность относительна, но всё же обычно довольно легко понять, что скрывается за значениями в вызове point3d(10, 50, 21)
или rgb(0, 255, 0)
. Тут, увы, работает только здравый смысл.
Во-вторых, нет ни смысла, ни возможности, указать по именам аргументы, объявленные через "звёздочку":
def sum(*args):
…
sum(x1=1, x2=2)
# TypeError: sum() got an unexpected keyword argument 'x1'
В таких функциях имя args
недоступно извне, ведь это не один аргумент, а получатель произвольного их количества.
Вам ответят команда поддержки Хекслета или другие студенты.
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
Наши выпускники работают в компаниях:
С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.
Зарегистрируйтесь или войдите в свой аккаунт