Модификация элементов списка в цикле (python)

Я пытаюсь изменить элементы в списке с помощью цикла for, но получаю сообщение об ошибке (см. ниже). Образец кода:

#!/usr/bin/env python
# *-* coding: utf8 *-*

data = []
data.append("some")
data.append("example")
data.append("data")
data.append("here")

for item in data:
    data[item] = "everything"

Ошибка:

Traceback (most recent call last):
  File "./testy.py", line 11, in <module>
    data[item] = "everything"
TypeError: list indices must be integers, not str

Есть ли способ решить эту проблему?


person Mateusz Jagiełło    schedule 04.07.2010    source источник


Ответы (3)


Попробуйте это вместо этого:

for i in xrange(len(data)):
    data[i] = "everything"

Основная проблема, с которой вы сталкиваетесь, заключается в том, что когда вы пишете data[i], где data является списком, i должно быть целым числом, числовым индексом в списке. Но в петле

for item in data

item — это фактическая вещь в списке, т. е. строка, а не числовой индекс вещи. xrange — это итератор, который выдает числа вместо значений в списке, так что вы можете его использовать.

Альтернативой было бы

for i, _ in enumerate(data):
    data[i] = "everything"

Функция enumerate дает вам итератор для кортежей формы (index, item), поэтому все, что вам нужно сделать, это взять индекс и забыть об элементе. Я не уверен, что так или иначе (enumerate или xrange) будет значительно быстрее или лучше, поскольку я думаю, что списки сохраняют свою длину в переменной, чтобы к ней можно было быстро получить доступ, не считая элементов списка.

Однако, если вам нужно старое значение списка для вычисления нового значения списка, способ enumerate, вероятно, будет немного быстрее, потому что вы не заставляете Python искать элемент в списке:

for i, item in enumerate(data):
    data[i] = func(item)

Однако такие вещи лучше выражать как понимание списка:

data = [func(item) for item in data]

Когда вы сделаете это, Python будет просматривать каждый элемент в data, применять к нему функцию и автоматически создавать новый список из результатов, поэтому вам не нужно беспокоиться о том, чтобы поместить результат func(item) в нужное место в списке. список. Ваш исходный пример может быть выражен как

data = ["everything" for item in data]
person David Z    schedule 04.07.2010
comment
Это выглядит немного странно (или обходной путь), но работает корректно. Я не знал, что переопределяющие элементы (в списке) должны иметь свой идентификатор. Спасибо. - person Mateusz Jagiełło; 04.07.2010
comment
@sigo: на самом деле это вовсе не обходной путь, это 100% правильный и совершенно нормальный способ выполнения такого рода задач (но обратите внимание на то, что я сказал о понимании списков). - person David Z; 04.07.2010
comment
В этом конкретном случае понимание списка может быть заменено более быстрым data = ["everything"] * len(data). - person Eric O Lebigot; 04.07.2010
comment
Дополнительное примечание о потреблении памяти и понимании списков: для этого потребуется (временно) память для хранения старого data и нового data. Следовательно, для больших списков индексированная модификация может быть предпочтительнее. - person norok2; 24.10.2018

Доступ к элементам списка осуществляется по целочисленному индексу, т.е. е. в вашем примере data[1] == 'example'. Вот почему Python жалуется, когда вы используете строку для поиска.

Если вы хотите найти элемент в списке по его значению, вы можете использовать data.index("value"):

data[data.index("some")] = "something else"

Но если вы просто хотите перебрать их, используйте enumerate(), как предложил Дэвид.

person Tim Pietzcker    schedule 04.07.2010

индексация списка с использованием целых чисел может быть неэффективной. Вполне вероятно, что python хранит элементы списка, используя связанную таблицу с базовыми указателями. В этом случае, чтобы найти конкретный элемент, python должен пройти по списку до i-го элемента.

Предполагается, что использование такого формата может быть эффективным: a[:] = [x*x for x in a]

person Jingpeng Wu    schedule 06.08.2015