Попробуйте угадать, что выведет этот код. numbers = [[1, 2], [3, 4]] copy = numbers.copy() copy[0].append(99) print(numbers) Если слово «копия» понимать буквально, то ответ кажется очевидным. Мы изменили копию. Значит, оригинал должен остаться прежним. Многие ожидают увидеть: [[1, 2], [3, 4]] Но Python выводит совсем другое: [[1, 2, 99], [3, 4]] Получается странная ситуация. Мы изменяли копию, а изменился оригинал. Неужели метод copy() работает неправильно? На самом деле метод работает именно так, как задумывался. Проблема в другом. Мы привыкли думать о копировании как о создании полностью независимого объекта...
Python без магии
Почему `+=` иногда создаёт новый объект, а иногда нет?
Попробуйте угадать, что выведет этот код. x = 10 print(id(x)) x += 5 print(id(x)) Многие ожидают, что += просто изменит значение переменной. Но если посмотреть на id(), окажется, что после выполнения операции объект стал другим. Получается, что оператор += создал новый объект. Теперь посмотрим почти такой же пример. numbers = [1, 2] print(id(numbers)) numbers += [3] print(id(numbers)) На этот раз id() остаётся прежним. Получается совершенно противоположное поведение. В одном случае объект изменился. В другом — нет. Почему? Если вспомнить предыдущие статьи, то ответ уже почти лежит на поверхности...
Почему нельзя писать `def func(items=[])`
Дисклеймер: Предполагается, что вы уже умеете писать простые программы на Python и знаете базовый синтаксис (if, for, функции, списки). Здесь мы разбираем не как пользоваться языком, а почему он работает именно так. Попробуйте угадать, что выведет этот код: def add(item, items=[]): items.append(item) return items print(add(1)) print(add(2)) print(add(3)) Если вы ещё не сталкивались с этой особенностью Python, скорее всего, ожидание будет таким: [1] [2] [3] Ведь каждый вызов функции кажется совершенно независимым от предыдущего. Однако Python выводит совсем другой результат: [1] [1, 2] [1, 2, 3] Получается, что список каким-то образом “запомнил” предыдущие вызовы функции...
Чем отличаются is и == ?
Если спросить начинающего Python-разработчика, чем отличаются операторы is и ==, то чаще всего можно услышать что-то вроде: Это распространённый ответ. И хотя в нём есть доля правды, он не совсем точный. Давайте разберёмся, что происходит на самом деле. Начнём с простого примера. a = [1, 2, 3] b = [1, 2, 3] print(a == b) print(a is b) Результат будет таким: True False На первый взгляд это выглядит странно. Если списки одинаковые, почему один оператор говорит True, а другой - False? Чтобы ответить на этот вопрос, давайте вспомним то, что мы уже знаем из предыдущих статей. Каждая переменная в Python содержит не объект, а имя, которое на него ссылается...
Что такое изменяемые и неизменяемые объекты?
В предыдущей статье мы столкнулись с довольно любопытным наблюдением. Списки можно изменять: numbers = [1, 2] numbers.append(3) print(numbers) Результат: [1, 2, 3] А вот с числами похожий трюк не работает. Когда мы пишем: x = 10 x = 20 объект со значением 10 не превращается в объект со значением 20. Вместо этого имя x начинает ссылаться на другой объект. На первый взгляд это выглядит как два совершенно разных поведения. На самом деле Python делит все объекты на две большие группы. Первая группа называется изменяемыми объектами (mutable objects). Вторая - неизменяемыми объектами (immutable objects)...
