На этом шаге мы рассмотрим способы создания списка.
Создать список можно следующими способами:
>>> list() # Создаем пустой список [] >>> list("String") # Преобразуем строку в список ['S', 't', 'r', 'i', 'n', 'g'] >>> list((1, 2, 3, 4, 5)) # Преобразуем кортеж в список [1, 2, 3, 4, 5]
>>> arr = [1, "str", 3, "4"] >>> arr [1, 'str', 3, '4']
>>> arr = [] # Создаем пустой список >>> arr.append(1) # Добавляем элемент1 (индекс 0) >>> arr.append("str") # Добавляем элемент2 (индекс 1) >>> arr [1, 'str']
В некоторых языках программирования (например, в РНР) можно добавить элемент, указав пустые квадратные скобки или индекс больше последнего индекса. В языке Python все эти способы приведут к ошибке:
>>> arr = [] >>> arr[] = 10 SyntaxError: invalid syntax
При создании списка в переменной сохраняется ссылка на объект, а не сам объект. Это обязательно следует учитывать при групповом присваивании. Групповое присваивание можно использовать для чисел и строк, но для списков этого делать нельзя. Рассмотрим пример:
>>> х = y = [1, 2] # Якобы создали два объекта >>> х, y ([1, 2], [1, 2])
В этом примере мы создали список из двух элементов и присвоили значение переменным х и у. Теперь попробуем изменить значение в переменной у:
>>> y[1] = 100 # Изменяем второй элемент >>> х, y # Изменилось значение сразу в двух переменных ([1, 100], [1, 100])
Как видно из примера, изменение значения в переменной у привело также к изменению значения в переменной х. Таким образом, обе переменные ссылаются на один и тот же объект, а не на два разных объекта. Чтобы получить два объекта, необходимо производить раздельное присваивание:
>>> х, y = [1, 2], [1, 2] >>> y[1] = 100 # Изменяем второй элемент >>> х, y ([1, 2], [1, 100])
Точно такая же ситуация возникает при использовании оператора повторения *. Например, в следующей инструкции производится попытка создания двух вложенных списков с помощью оператора *:
>>> arr =[[]] * 2 # Якобы создали два вложенных списа >>> arr [[], []] >>> arr[0].append(5) # Добавляем элемент >>> arr # Изменились два элемента [[5], [5]]
Создавать вложенные списки следует с помощью метода append() внутри цикла:
>>> arr = [] >>> for i in range(2): arr.append([]) >>> arr [[], []] >>> arr[0].append(5); arr [[5], []]
Можно также воспользоваться генераторами списков:
>>> arr = [[] for i in range(2)] >>> arr [[], []] >>> arr[0].append(5); arr [[5], []]
Проверить, ссылаются ли две переменные на один и тот же объект, позволяет оператор is. Если переменные ссылаются на один и тот же объект, то оператор is возвращает значение True:
>>> х = y = [1, 2] # Неправильно >>> х is y # Переменные содержат ссыпку на один и тот же список True >>> х, y = [1, 2], [1, 2] # Правильно >>> х is y # Это разные объекты False
Но что же делать, если необходимо создать копию списка? Первый способ заключается в применении операции извлечения среза, второй - в использовании функции list(), а третий - в применении появившегося в Python 3.3 метода сору().
>>> x = [1, 2, 3, 4, 5] # Создали список >>> # Создаем копию списка >>> y = list(x) # или с помощью среза: y = x[:] >>> # или вызовом метода copy(): y = x.copy() >>> y [1, 2, 3, 4, 5] >>> x is y # Оператор показывает, что это разные объекты False >>> y[1] = 100 # Изменяем второй элемент >>> x, y ([1, 2, 3, 4, 5], [1, 100, 3, 4, 5])
На первый взгляд может показаться, что мы получили копию - оператор is показывает, что это разные объекты, а изменение элемента затронуло лишь значение переменной у. В данном случае вроде все нормально. Но проблема заключается в том, что списки в языке Python могут иметь неограниченную степень вложенности. Рассмотрим это на примере:
>>> x = [1, [2, 3, 4, 5]] # Создали вложенный список >>> y = list(x) # Якобы сделали копию списка >>> x is y # Разные объекты False >>> y[1][1] = 100 # Изменяем элемент >>> x, y # Изменение затронуло переменную x! ([1, [2, 100, 4, 5]], [1, [2, 100, 4, 5]])
В этом примере мы создали список, в котором второй элемент является вложенным списком. Далее с помощью функции list() попытались создать копию списка. Как и в предыдущем примере, оператор is показывает, что это разные объекты, но посмотрите на результат. Изменение переменной у затронуло и значение переменной х. Таким образом, функция list() и операция извлечения среза создают лишь поверхностную копию списка.
Чтобы получить полную копию списка, следует воспользоваться функцией deepcopy() из модуля сору:
>>> import copy # Подключаем модуль copy >>> x = [1, [2, 3, 4, 5]] >>> y = copy.deepcopy(x) # Делаем полную копию списка >>> y[1][1] = 100 # Изменяем второй элемент >>> x, y # Изменился только список в переменной y ([1, [2, 3, 4, 5]], [1, [2, 100, 4, 5]])
Функция deepcopy() создает копию каждого объекта, при этом сохраняя внутреннюю структуру списка. Иными словами, если в списке существуют два элемента, ссылающиеся на один объект, то будет создана копия объекта, и элементы будут ссылаться на этот новый объект, а не на разные объекты. Пример:
>>> import copy # Подключаем модуль copy >>> x = [1, 2] >>> y = [x, x] # Два элемента ссылаются на один объект >>> y [[1, 2], [1, 2]] >>> z = copy.deepcopy(y) # Сделали копию списка >>> z[0] is x, z[1] is x, z[0] is z[1] (False, False, True) >>> z[0][0] = 300 # Изменили один элемент >>> z # Значение изменилось сразу в двух элементах! [[300, 2], [300, 2]] >>> x # начальный список не изменился [1, 2]
На следующем шаге мы рассмотрим операции над списками.