Классическая задача со списками: задача с собеседования
Самая любимая, можно сказать, классическая задача, на собеседованиях — задача со списками. Эта задача позволяет оценить не только умение кандидата писать код, но и его понимание фундаментальных концепций 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 внутри функции гарантирует, что при каждом вызове без явного списка создается новый пустой список, и таким образом каждый вызов имеет свой собственный список.