Самая любимая, можно сказать, классическая задача, на собеседованиях — задача со списками. Эта задача позволяет оценить не только умение кандидата писать код, но и его понимание фундаментальных концепций Python, способность анализировать результаты и находить ошибки, а также умение документировать свой код.
Задача:
Реализуйте функцию add_to_list
, которая добавляет элемент item
в список my_list
и возвращает этот список.
# use provided code below to verify your implementation
def add_to_list(item, my_list=[]):
# enter your code here
return my_list
x = add_to_list(1)
print(x)
y = add_to_list(2)
print(y)
z = add_to_list(3, [4, 5])
print(z)
1. Какие значения вы получили для переменных x
, y
, и z
при выполнении кода?
x = [1]
y = [1, 2]
z = [4, 5, 3]
2. Чему равно значение y
? Объяснить, что происходит.
В Python, когда функция определяет аргумент по умолчанию как изменяемый объект (в данном случае, пустой список), этот объект создается только один раз при определении функции, а не при каждом её вызове, если список явно не передан.
При первом вызове add_to_list(1) был создан список [1].
При втором вызове add_to_list(2) используется тот же самый список, а не создается новый, и поэтому к нему добавляется элемент 2, что дает [1, 2].
3. Чем отличается поведение вызова add_to_list(3, [4, 5])
от двух предыдущих вызовов?
В случае вызова add_to_list(3, [4, 5]), мы явно передали список [4, 5] в качестве аргумента my_list, поэтому функция использовала этот новый список, а не тот, что был определен по умолчанию.
Задачи:
1. Исправить функцию add_to_list
, чтобы она работала корректно, и вызовы add_to_list(1)
и add_to_list(2)
создавали отдельные списки, а не использовали один и тот же.
2. Написать docstring
для исправленной функции.
3. Добавить аннотацию типов для входных и выходных параметров функции.
4. Объяснить, почему исправление работает, и какие изменения были внесены.
docstring
)def add_to_list(item: int, my_list: list = None) -> list:
"""Добавление элемента в список
Аргументы:
:param item: элемент, который нужно добавить в список
:param my_list: список, в который нужно добавить элемент
Возвращает:
:param list: список с добавленным элементом
"""
if my_list is None:
my_list = []
my_list.append(item)
return my_list
x = add_to_list(1)
print(x)
y = add_to_list(2)
print(y)
z = add_to_list(3, [4, 5])
print(z)
Функция использует None в качестве значения по умолчанию для my_list, а внутри функции проверяет, является ли my_list = None. Если да, то создается новый список.
Проблема заключалась в том, что изменяемый объект (список) создавался один раз при определении функции, что приводило к нежелательному поведению. Стоит учитывать, что при передаче существующего списка, мы не создаем копию перед вставкой, а добавляем напрямую в существующий. А отсюда следует, что если мы хотим иметь новый список — решение должно быть доработано.
Использование None в качестве значения по умолчанию и проверка на None внутри функции гарантирует, что при каждом вызове без явного списка создается новый пустой список, и таким образом каждый вызов имеет свой собственный список.