Все об аргументах функций Python: от основ до продвинутых техник
Что такое аргументы функции и зачем они нужны
Аргументы (parameters) в Python - это данные, которые передаются функции при её вызове. Они позволяют делать функцию гибкой и переиспользуемой. В Python существует несколько способов объявления и передачи аргументов, каждый из которых подходит для определённых сценариев.
Как писать универсальные функции, которые принимают разное количество аргументов?
Наиболее эффективный способ - комбинировать позиционные аргументы, аргументы по умолчанию, а также использовать *args и **kwargs. Это позволяет создавать функции, которые могут обрабатывать как обязательные, так и необязательные данные.
def create_profile(name, age, *hobbies, **extra):
"""Создаёт словарь профиля пользователя."""
profile = {
'name': name,
'age': age,
'hobbies': list(hobbies) if hobbies else None
}
profile.update(extra)
return profile
# Примеры вызова
print(create_profile('Alice', 30, 'reading', 'swimming', city='NYC', job='engineer'))
print(create_profile('Bob', 25))
print(create_profile('Charlie', 35, 'gaming', city='London'))аргументы print python (аргументы функции print в python)
{
'name': 'Alice',
'age': 30,
'hobbies': ['reading', 'swimming'],
'city': 'NYC',
'job': 'engineer'
}
{
'name': 'Bob',
'age': 25,
'hobbies': None,
}
{
'name': 'Charlie',
'age': 35,
'hobbies': ['gaming'],
'city': 'London'
}Python 3 аргументы (аргументы в python 3)
В этом примере name и age - обязательные позиционные аргументы. *hobbies собирает все переданные после них позиционные аргументы в кортеж. **extra собирает все именованные аргументы в словарь. Такая конструкция позволяет создавать очень гибкие API.
Типичная ошибка: попытка передать именованный аргумент до позиционного после распаковки *args. Python запрещает это, так как после *args все позиционные аргументы должны передаваться только по имени.
# Ошибка! Нельзя имя после *args
# create_profile('Alice', 30, 'hobbies', city='NYC') # hobbies воспримется как часть *argsаргумент параметр python (аргументы и параметры в python)
Решение: строго соблюдать порядок: обязательные позиционные, *args, именованные со значением по умолчанию, **kwargs.
Как сделать некоторые аргументы необязательными?
Используйте значения по умолчанию. Это позволяет вызывать функцию без указания этих аргументов.
def greet(name, greeting='Привет'):
return f'{greeting}, {name}!'
print(greet('Анна'))
print(greet('Пётр', 'Здравствуйте'))аргумент класса python (аргументы класса python)
Привет, Анна! Здравствуйте, Пётр!
Python аргументы строки (аргументы строки в python (командная строка))
Ошибка: использование изменяемого объекта (список, словарь) в качестве значения по умолчанию. Значение по умолчанию вычисляется только один раз при определении функции, и все вызовы будут использовать один и тот же объект.
def add_item(item, container=[]):
container.append(item)
return container
print(add_item('a'))
print(add_item('b')) # Ожидаем ['b'], а получаем ['a', 'b']аргумент метода python (аргументы метода python)
['a'] ['a', 'b']
Python args (аргументы в python)
Решение: использовать None и создавать новый объект внутри функции.
def add_item(item, container=None):
if container is None:
container = []
container.append(item)
return container
print(add_item('a'))
print(add_item('b'))именованные аргументы функции python (именованные аргументы функции python)
['a'] ['b']
именованные аргументы python (именованные аргументы python)
Как заставить передавать аргументы только по имени (keyword-only)?
После аргумента * (не путать с *args) все следующие аргументы становятся обязательными именованными.
def connect(host, port, *, timeout=10, ssl=True):
print(f'Connecting to {host}:{port}, timeout={timeout}, ssl={ssl}')
connect('localhost', 8080)
connect('localhost', 8080, timeout=30, ssl=False)
# Следующий вызов вызовет ошибку
# connect('localhost', 8080, 30) # TypeError: connect() takes 2 positional arguments but 3 were givenколичество аргументов функции python (количество аргументов функции python)
Connecting to localhost:8080, timeout=10, ssl=True Connecting to localhost:8080, timeout=30, ssl=False
параметры и аргументы функции python (параметры и аргументы функции python)
Это повышает читаемость кода и предотвращает случайную передачу неверного порядка.
Как передать произвольное количество именованных аргументов?
Использование **kwargs позволяет функции принимать любые ключевые аргументы в виде словаря.
def show_config(**kwargs):
for key, value in kwargs.items():
print(f'{key} = {value}')
show_config(db_host='localhost', db_port=5432, debug=True)Python передать аргументы (передача аргументов в python)
db_host = localhost db_port = 5432 debug = True
Python принять аргументы (приём аргументов в python)
Это удобно для конфигураций, обёрток и декораторов.
Как использовать аннотации типов для аргументов?
Аннотации не влияют на выполнение, но улучшают читаемость и помогают IDE и линтерам.
def calc_sum(numbers: list[int], start: int = 0) -> int:
return start + sum(numbers)
result = calc_sum([1,2,3], 10)
print(result)Python список аргументов (список аргументов в python)
16
Современные инструменты (mypy, pyright) могут статически проверять типы.
Расширенные примеры работы с аргументами
Комбинирование всех видов аргументов в одной функции
def register_user(
username: str,
email: str,
*groups: str,
is_active: bool = True,
**extra: any
) -> dict:
"""Регистрирует пользователя с группами и дополнительными полями."""
user = {
'username': username,
'email': email,
'groups': list(groups),
'active': is_active
}
user.update(extra)
return user
# Вызов с разными наборами аргументов
user1 = register_user('ivan', 'ivan@example.com', 'admins', 'users', is_active=False)
user2 = register_user('maria', 'maria@example.com', 'vip', phone='+12345', age=30)
user3 = register_user('guest', 'guest@example.com')
print(user1)
print(user2)
print(user3){
'username': 'ivan',
'email': 'ivan@example.com',
'groups': ['admins', 'users'],
'active': False
}
{
'username': 'maria',
'email': 'maria@example.com',
'groups': ['vip'],
'active': True,
'phone': '+12345',
'age': 30
}
{
'username': 'guest',
'email': 'guest@example.com',
'groups': [],
'active': True
}Обратите внимание: *groups собирает все позиционные аргументы, переданные после email, в кортеж. Если передать только обязательные, кортеж будет пуст. Именованный is_active имеет значение по умолчанию, но может быть переопределён. **extra принимает любые дополнительные именованные аргументы.
Распаковка аргументов из последовательностей и словарей
def point(x, y, z):
return f'Point({x}, {y}, {z})'
# Распаковка списка/кортежа
coords = [10, 20, 30]
print(point(*coords))
# Распаковка словаря (ключи должны совпадать с именами параметров)
data = {'x': 100, 'y': 200, 'z': 300}
print(point(**data))
# Смешанная распаковка
base = (1, 2)
extra = {'z': 3}
print(point(*base, **extra))Point(10, 20, 30) Point(100, 200, 300) Point(1, 2, 3)
Распаковка часто используется при передаче динамических наборов данных в функции. Ошибка возникает, если количество элементов не совпадает с количеством параметров или ключи не соответствуют именам.
Аргументы только по ключу (keyword-only) с *args
def process_data(*items, separator=', ', prefix='data:'):
"""Объединяет элементы с разделителем и префиксом."""
result = separator.join(str(item) for item in items)
return f'{prefix}{result}'
print(process_data(1, 2, 3))
print(process_data('a', 'b', 'c', separator=' - ', prefix='Result: '))data:1,2,3 Result: a - b - c
Здесь separator и prefix могут быть переданы только по имени, так как они находятся после *items. Это предотвращает путаницу: если бы separator был третьим позиционным, его можно было бы случайно передать как элемент.
Использование аргументов по умолчанию с замыканиями
def power_factory(exponent):
def power(base, exp=exponent):
return base ** exp
return power
square = power_factory(2)
cube = power_factory(3)
print(square(5))
print(cube(5))
# Можно переопределить экспоненту
print(square(5, exp=3))25 125 125
Значение по умолчанию для exp фиксируется во время определения внутренней функции. Это удобно для создания параметризованных функций.
Аргументы и декораторы
def debug(func):
def wrapper(*args, **kwargs):
print(f'Calling {func.__name__} with args={args}, kwargs={kwargs}')
result = func(*args, **kwargs)
print(f'Result: {result}')
return result
return wrapper
@debug
def multiply(x, y):
return x * y
multiply(3, 4)
multiply(x=5, y=6)Calling multiply with args=(3, 4), kwargs={}
Result: 12
Calling multiply with args=(), kwargs={'x': 5, 'y': 6}
Result: 30Декоратор debug принимает любые аргументы исходной функции и передаёт их дальше. Это стандартный шаблон для обёрток.
Типичные проблемы с изменяемыми аргументами по умолчанию (глубокое копирование)
def bad_default(items=[]):
items.append(1)
return items
# Первый вызов
print(bad_default())
print(bad_default())
# Правильное решение
from typing import List, Optional
def good_default(items: Optional[List[int]] = None) -> List[int]:
if items is None:
items = []
items.append(1)
return items
print(good_default())
print(good_default())
print(good_default([0]))[1] [1, 1] [1] [1] [0, 1]
Видно, что bad_default накапливает элементы, тогда как good_default каждый раз создаёт новый список, если не передан аргумент.
Аннотации типов и проверка с помощью pydantic (расширенный пример)
from pydantic import BaseModel
from typing import List, Optional
class User(BaseModel):
name: str
age: int
hobbies: List[str] = []
def create_user(data: User) -> dict:
return data.dict()
# Валидация происходит при создании объекта User
user = User(name='Anna', age=25, hobbies=['reading', 'coding'])
print(create_user(user))
# Попытка передать неверный тип вызовет исключение
# User(name='Bob', age='abc') # validation error{'name': 'Anna', 'age': 25, 'hobbies': ['reading', 'coding']}Это демонстрирует, как аннотации аргументов можно дополнить библиотеками для строгой валидации.