Блог пользователя Fefer_Ivan

Автор Fefer_Ivan, 14 лет назад, По-русски
Доброе утро/день/вечер/ночь, Codeforces!

Сегодня я впервые попробовал сдать несколько задач на Python.
Во время написание одной из них, я обнаружил что-то совсем непонятное в поведении вложенных списков:

Пусть нам нужен массив 2 на 2.

Пишем:
a = [[0]*2]*2
print "Before:"
print a
a[0][0] = 1
print "After:"
print a

Получаем:
Before:
[[0, 0], [0, 0]]
After:
[[1, 0], [1, 0]]

Вопрос: почему изменился второй список?

Если написать немного по-другому:
a = [[0]*2]
a.append([0]*2)
print "Before:"
print a
a[0][0] = 1
print "After:"
print a

Получаем:
Before:
[[0, 0], [0, 0]]
After:
[[1, 0], [0, 0]]

Вопрос: в чем разница?

Windows 7, 32-bit, Python 2.7.1
Строка запуска: python solution.py < input.txt
  • Проголосовать: нравится
  • +26
  • Проголосовать: не нравится

14 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится
Ну, в первом случае создается объект (значит, и ссылка на него), который потом дублируется два раза.
поэтому при всяком изменении первого элемента списка, будет меняться и второй. Во втором случае создается 2 разных объекта, которые инкапсулируются в список А.
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    А почему при использовании [0]*2 не получается такой же эффект?
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      просто примитивные типы копируются по значению
    • 14 лет назад, # ^ |
        Проголосовать: нравится +1 Проголосовать: не нравится
      Ну, причину ниже объяснили. Просто тут создался объект (в первом случае)  и именно он копировался.
      А во втором создались 2 независимых объекта в  различное время
14 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится
Списки скопировались по ссылке в первом случае. А во втором это совершенно разные списки.
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Как в таком случае легко создать многомерный массив?
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    ну можно че-нить типа

    a = []
    for  x in range(n):
    a.append([])
  • 14 лет назад, # ^ |
      Проголосовать: нравится +7 Проголосовать: не нравится
    Я делаю методом
    [[0]*n for _ in xrange(m)]
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Ну и вообще, например, копировать (да и создавать) массив m x n можно так:
    a = [[b[i][j] for j in range (n)] for i in range (m)]
    a = [[0 for j in range (n)] for i in range (m)]
    Есть ещё функция copy.deepcopy для копирования.
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      deepcopy еще импортировать надо
      А покопировать можно и так [x[:] for x in a]