Создать пустой список заданного размера в Python
Проблема с созданием и присвоением значений элементам списка в Python
Я пытаюсь создать пустой список, который может содержать 10 элементов. После этого я планирую присвоить значения элементам этого списка. Например, я использую следующий код:
xs = list()
for i in range(0, 9):
xs[i] = i
Однако при выполнении этого кода возникает ошибка IndexError: list assignment index out of range
.
Почему эта ошибка возникает, и как правильно создать список, чтобы присваивать значения его элементам?
5 ответ(ов)
Вы не можете присвоить значение элементу списка, используя синтаксис xs[i] = value
, если список не инициализирован, как минимум, с i+1
элементами (так как первый индекс равен 0). Вместо этого используйте xs.append(value)
, чтобы добавлять элементы в конец списка. (Хотя вы могли бы использовать такой синтаксис, если бы работали со словарем вместо списка.)
Создание пустого списка:
>>> xs = [None] * 10
>>> xs
[None, None, None, None, None, None, None, None, None, None]
Присвоение значения существующему элементу списка:
>>> xs[1] = 5
>>> xs
[None, 5, None, None, None, None, None, None, None, None]
Имейте в виду, что попытка выполнить xs[15] = 5
вызовет ошибку, так как наш список содержит только 10 элементов.
Функция range(x)
создает список чисел от [0, 1, 2, ... x-1]
.
# Только для версии 2.X. Используйте list(range(10)) в версии 3.X.
>>> xs = range(10)
>>> xs
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Использование функции для создания списка:
>>> def display():
... xs = []
... for i in range(9): # Это просто чтобы показать, как создать список.
... xs.append(i)
... return xs
...
>>> print display()
[0, 1, 2, 3, 4, 5, 6, 7, 8]
Генерация списка (использованы квадраты чисел, потому что для range
вам не нужно делать всего этого, вы можете просто вернуть range(0, 9)
):
>>> def display():
... return [x**2 for x in range(9)]
...
>>> print display()
[0, 1, 4, 9, 16, 25, 36, 49, 64]
Попробуйте вместо этого:
lst = [None] * 10
Этот код создаст список размером 10, в котором каждое место инициализировано значением None
. После этого вы можете добавлять элементы в него:
lst = [None] * 10
for i in range(10):
lst[i] = i
Тем не менее, это не самый "питонический" способ делать вещи. Лучше сделать так:
lst = []
for i in range(10):
lst.append(i)
Или даже проще, в Python 2.x вы можете сделать так, чтобы инициализировать список со значениями от 0 до 9:
lst = range(10)
А в Python 3.x:
lst = list(range(10))
Ваша проблема связана с тем, что когда вы создаете список списков в Python с помощью оператора умножения, как в примере a = [[]]*10
, все элементы списка ссылаются на один и тот же объект. Это означает, что если вы измените один из вложенных списков, это изменение отразится на всех остальных, так как они указывают на один и тот же объект в памяти.
Пример, который вы привели:
>>> a = [[]]*10
>>> a[0].append(0)
>>> a
[[0], [0], [0], [0], [0], [0], [0], [0], [0], [0]]
Благодаря этому видим, что все 10 списков задействовали один и тот же вложенный список.
Чтобы избежать такой ситуации и создать независимые списки, можно использовать функцию, создающую новый объект для каждого элемента:
def init_list_of_objects(size):
list_of_objects = []
for i in range(size):
list_of_objects.append([]) # создаем новый объект в каждой итерации
return list_of_objects
>>> a = init_list_of_objects(10)
>>> a
[[], [], [], [], [], [], [], [], [], []]
>>> a[0].append(0)
>>> a
[[0], [], [], [], [], [], [], [], [], []]
Таким образом, каждый элемент списка a
является отдельным объектом, что позволяет избежать проблем с ссылками.
Также, как вы отметили в редакции, существует более короткий и "питонистый" способ сделать то же самое с помощью генератора списков:
>>> a = [[] for _ in range(10)]
Это создает список из 10 отдельных списков, не связанных между собой, и проблема с общими ссылками больше не возникает.
Так что ваш подход с генератором списков — это действительно предпочтительный и более лаконичный способ создания списка списков в Python!
Меня удивляет, что никто не предложил этот простой способ создания списка из пустых списков. Хотя это старая тема, я добавлю это для полноты картины. Вот как можно создать список из 10 пустых списков:
x = [[] for i in range(10)]
Существует два «быстрых» способа создания списка:
x = длина_вашего_списка
a = [None] * x
# или
a = [None for _ in range(x)]
Похоже, что способ [None] * x
работает быстрее:
>>> from timeit import timeit
>>> timeit("[None]*100", number=10000)
0.023542165756225586
>>> timeit("[None for _ in range(100)]", number=10000)
0.07616496086120605
Но если вас устраивает диапазон (например, [0,1,2,3,...,x-1]
), тогда range(x)
может быть самым быстрым решением:
>>> timeit("range(100)", number=10000)
0.012513160705566406
Таким образом, если вам нужен список, заполненный None
, используйте [None] * x
для повышения производительности. Если же вам нужен список с последовательными числами, range(x)
будет лучшим выбором.
Почему используется string.join(list), а не list.join(string)?
Как клонировать список, чтобы он не изменялся неожиданно после присваивания?
Как вернуть ключи словаря в виде списка в Python?
Как отсортировать список/кортеж списков/кортежей по элементу на заданном индексе
Как преобразовать строковое представление списка в список?