Входные параметры в Python: базовые и продвинутые способы
Входные параметры функций в Python
Основной способ передачи данных в функцию – использование позиционных и именованных аргументов с возможностью указания значений по умолчанию. Это покрывает большинство практических случаев и делает код читаемым.
def greet(name, greeting="Hello", punctuation="!"):
print(f"{greeting}, {name}{punctuation}")
greet("Анна") # Hello, Анна!
greet("Пётр", "Привет") # Привет, Пётр!
greet("Мария", greeting="Здравствуйте") # Здравствуйте, Мария!аргументы print python (аргументы функции print в python)
В примере name – обязательный позиционный аргумент, greeting и punctuation имеют значения по умолчанию. При вызове можно передать только обязательные аргументы, либо указать любые комбинации именованных.
Типичная ошибка: использование изменяемого объекта (например, списка) в качестве значения по умолчанию. Этот объект создаётся однократно и будет общим для всех вызовов, что может привести к неожиданным результатам.
def add_item(item, lst=[]):
lst.append(item)
return lst
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] – неожиданно!Python 3 аргументы (аргументы в python 3)
Исправление: использовать None и создавать список внутри функции.
def add_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lstаргумент параметр python (аргументы и параметры в python)
Как передать произвольное количество позиционных аргументов?
Используется синтаксис *args. Звёздочка перед именем параметра упаковывает все переданные позиционные аргументы в кортеж.
def sum_all(*numbers):
return sum(numbers)
print(sum_all(1, 2, 3)) # 6
print(sum_all(10, 20)) # 30аргумент класса python (аргументы класса python)
Имя args – общепринятое, может быть любым. Используется, когда количество аргументов заранее неизвестно.
Проблема: если после *args определить ещё один позиционный параметр, его можно передать только по имени (ключевому слову).
def func(*args, extra):
print(args, extra)
func(1, 2, extra=3) # (1, 2) 3Python аргументы строки (аргументы строки в python (командная строка))
Как передать произвольное количество именованных аргументов?
Используется **kwargs (keyword arguments). Две звёздочки упаковывают именованные аргументы в словарь.
def print_person(**info):
for key, value in info.items():
print(f"{key}: {value}")
print_person(name="Иван", age=30, city="Москва")аргумент метода python (аргументы метода python)
name: Иван age: 30 city: Москва
Python args (аргументы в python)
Имя kwargs тоже условное. Параметр **kwargs помещается в определении функции последним.
Ошибка: попытка передать позиционные аргументы после **kwargs или объявить ещё один именованный параметр после него приведёт к синтаксической ошибке.
Как задать значения по умолчанию и избежать побочных эффектов?
Значения по умолчанию вычисляются один раз в момент определения функции. Для изменяемых объектов (списки, словари) это ведёт к проблеме, описанной выше. Рекомендуется использовать None и проверять внутри тела функции.
def create_user(name, roles=None):
if roles is None:
roles = []
roles.append("user")
return {name: roles}
print(create_user("Анна")) # {'Анна': ['user']}
print(create_user("Борис")) # {'Борис': ['user']}именованные аргументы функции python (именованные аргументы функции python)
Распространённая оплошность: забыть проверить None и напрямую модифицировать переданный изменяемый объект, что может изменить внешние данные.
Как явно указать ожидаемый тип аргумента?
Аннотации типов (type hints) не проверяются интерпретатором, но помогают разработчикам и инструментам статического анализа (mypy).
def repeat(text: str, times: int) -> str:
return text * times
print(repeat("Ha", 3)) # HaHaHaименованные аргументы python (именованные аргументы python)
Аннотации указываются после двоеточия, возвращаемый тип – после ->. Сторонние библиотеки могут выполнять проверку во время выполнения.
Проблема: путаница между аннотациями и приведением типов. Аннотации не преобразуют аргументы; если передать не тот тип, ошибка не возникнет (до выполнения кода).
Как передать аргументы из списка или словаря?
Операторы распаковки * и ** применяются не только в определении функции, но и при её вызове.
def point(x, y, z):
return (x, y, z)
coords = [10, 20, 30]
dict_coords = {"x": 1, "y": 2, "z": 3}
print(point(*coords)) # (10, 20, 30)
print(point(**dict_coords)) # (1, 2, 3)
Распаковка удобна, когда данные уже находятся в структуре, соответствующей сигнатуре функции.
Ошибка: несовпадение количества элементов в коллекции с числом параметров (при распаковке списка) или несовпадение ключей словаря с именами параметров.
Расширенные примеры
Комбинирование *args и **kwargs
Функция может одновременно принимать произвольное количество позиционных и именованных аргументов. Порядок параметров: сперва обычные, затем *args, потом именованные со значением по умолчанию и **kwargs.
def flexible(a, b, *args, opt="default", **kwargs):
print(f"a={a}, b={b}, args={args}, opt={opt}, kwargs={kwargs}")
flexible(1, 2, 3, 4, opt="custom", name="test", version=1.0)
a=1, b=2, args=(3, 4), opt=custom, kwargs={'name': 'test', 'version': 1.0}
Передача произвольных аргументов в декоратор
Декоратор может принимать аргументы через вложенные функции с *args и **kwargs.
def repeat_decorator(times=1):
def decorator(func):
def wrapper(*args, **kwargs):
result = None
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat_decorator(times=3)
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Мир")
Hello, Мир! Hello, Мир! Hello, Мир!
Использование * для разделения позиционных и именованных аргументов
Если в определении функции присутствует одиночная звёздочка, все аргументы после неё могут быть переданы только по имени (ключевому слову).
def exact(a, b, *, c, d):
return a + b + c + d
print(exact(1, 2, c=3, d=4)) # 10
# exact(1, 2, 3, 4) # TypeError: exact() takes 2 positional arguments but 4 were given
Аннотации типов с использованием Union и Optional
Для указания нескольких возможных типов или необязательного параметра применяются конструкции из модуля typing.
from typing import Union, Optional
def example(value: Union[int, str], multiplier: Optional[int] = None) -> str:
if multiplier:
return str(value * multiplier)
return str(value)
print(example(5, 3)) # 15
print(example("Hello", 2)) # HelloHello
print(example(42)) # 42
Частичное применение аргументов с functools.partial
С помощью partial можно зафиксировать некоторые аргументы функции, создав новую функцию с меньшим числом параметров.
from functools import partial
def power(base, exponent):
return base ** exponent
square = partial(power, exponent=2)
cube = partial(power, exponent=3)
print(square(5)) # 25
print(cube(2)) # 8
Проверка аргументов во время выполнения с помощью assert
Для жёсткого контроля можно использовать assert или сторонние библиотеки вроде pydantic.
def positive_sum(a: int, b: int) -> int:
assert a > 0 and b > 0, "Аргументы должны быть положительными"
return a + b
print(positive_sum(3, 4)) # 7
# print(positive_sum(-1, 5)) # AssertionError
Именованные аргументы с ключами, содержащими дефис или пробелы
Имена параметров в Python – корректные идентификаторы, поэтому ключи с дефисами передать напрямую нельзя. Решение – использовать распаковку словаря.
def process(data):
print(data)
params = {"content-type": "application/json", "x-api-key": "123"}
process(params)
Принудительное указание именованных аргументов с *
В функциях с множеством параметров полезно заставить вызывающего указывать имена последних аргументов для улучшения читаемости.
def create_user(name, age, *, email, phone):
pass
create_user("Иван", 30, email="ivan@example.com", phone="+7-999-111-22-33")
# create_user("Иван", 30, "ivan@example.com", "+7-999-111-22-33") # TypeError
Переменное число аргументов с сохранением типа (typing.Protocol)
Для статической типизации произвольных аргументов можно определить протокол или использовать TypeVar, но это выходит за рамки основ.