Передача аргументов в функцию

Как в python передаются аргументы в функцию?

подробнее

Есть 2 типа передачи аргументов в функцию: по ссылке и по значению. В python аргументы передаются по ссылке.

# Пример:
a = [1, 2, 3]
def foo(arg):
    print(arg is a)
foo(a)  # True

Что такое *args и **kwargs?

подробнее
  • *args — позволяет функции принимать произвольное количество позиционных аргументов (упаковывает их в кортеж)
  • **kwargs — позволяет функции принимать произвольное количество именованных аргументов (упаковывает их в словарь)
# пример
def my_function(arg1, arg2, *args, kwarg1=None, **kwargs):
    print(f"Обязательные аргументы: {arg1}, {arg2}")  # 1, 2
    print(f"Дополнительные позиционные: {args}")  # (3, 4, 5)
    print(f"Обязательный именованный: {kwarg1}")  # required
    print(f"Дополнительные именованные: {kwargs}")  # {'extra1': 'a', 'extra2': 'b'}

my_function(1, 2, 3, 4, 5, kwarg1="required", extra1="a", extra2="b")
# пример 2
def foo(*args, **kwargs):
    print(locals())
foo(1, 2, 3, a=1, b=2, c=3)  # {'args': (1, 2, 3), 'kwargs': {'a': 1, 'b': 2, 'c': 3}}

Значение изменяемого типа в качестве аргумента по умолчанию.

подробнее

Когда в качестве значения по умолчанию используется изменяемый объект (список, словарь, множество), он создается один раз во время определения функции, а не при каждом вызове.

Пример проблемы

# НЕПРАВИЛЬНО
def add_item(item, target_list=[]):
    target_list.append(item)
    return target_list

# Проблема:
list1 = add_item(1)
print(list1)  # [1]

list2 = add_item(2)
print(list2)  # [1, 2] - ОЖИДАЛИ [2]!
print(list1)  # [1, 2] - Исходный список тоже изменился!

Почему это происходит

def demonstrate_issue(default_list=[]):
    print(f"ID списка: {id(default_list)}")
    default_list.append("item")
    return default_list

# При каждом вызове используется один и тот же объект
result1 = demonstrate_issue()  # ID списка: 140234567890
result2 = demonstrate_issue()  # ID списка: 140234567890 (тот же!)

Пример исправления

# Использование None как значения по умолчанию
def add_item(item, target_list=None):
    if target_list is None:
        target_list = []  # Создаем новый список при каждом вызове
    target_list.append(item)
    return target_list