Перейти до змісту

Посилання у контейнерах

У списках і кортежах містяться не об'єкти, як може здатись на перший погяд, а посилання на об'єкти. Давайте переконаємось у цьому.

Створимо немутабельний кортеж, який буде містити у собі мутабельний список:

>>> t = ([1, 1], )
>>> l = t[0]
>>> l is t[0]
True
>>>

І тепер змінюємо список, який міститься у кортежі:

>>> l[0] = 7
>>> t
([7, 1],)
>>>

Так виходить що ми змінили незмінюваний кортеж? Ні, кортеж залишився таким як і був. Значенням кортежа є послідовність посилань на об'єкти, і ці посилання ніяк не змінились. Змінився об'єкт, на який вказує одне з посилань, яке міститься в кортежі.

Ще приклад. Створимо список, який містить у собі ще один список з трьох об'єктів:

>>> l = [[0, 0, 0]]
>>> inner_list = l[0]
>>> inner_list
[0, 0, 0]
>>> inner_list is l[0]
True
>>>

А тепер спробуємо зі списка l зробити матрицю три на три. Для цього скористаємось мультиплікацією послідовностей:

>>> matrix = l * 3
>>> matrix
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>>

Начебто отримали те, що хотіли. Спробуємо змінити елемент матриці у першому стовпчику першого ряда:

>>> matrix[0][0] = 7
>>> matrix
[[7, 0, 0], [7, 0, 0], [7, 0, 0]]
>>>

Не зовсім те, на що очікували... Що не так?

Уся справа у тому, що операція мультиплікації "розмножує" не самі об'єкти у послідовності, а посилання на них.

Стовримо список l трошки інакше:

>>> inner_list = [0, 0, 0]
>>> l = [inner_list]
>>> l
[[0, 0, 0]]
>>> l[0] is inner_list
True
>>>

І коли ми використовуємо мультиплікацію, то вираз:

matrix = l * 3

фактично означає:

matrix = [inner_list] * 3

В результаті отримуємо список у якому тричі повторюється посилання inner_list на один і той самий об'єкт:

[inner_list, inner_list, inner_list]

Отже вираз:

matrix[0][0] = 7

фактично означає:

inner_list[0] = 7

Так що створити матрицю використовуючи мультиплікацію послідовностей як наведено у прикладі нижче нажаль не вийде:

n = 5
matrix = [[0] * n] * n # так повноцінної матриці не отримати!