В Python есть ли способ обновить контейнер с помощью конструкции в стиле foreach? - PullRequest
0 голосов
/ 24 октября 2018

Я предполагал, что конструкция в стиле foreach в Python позволит мне обновить мой список, как это делает в C#.Это не так.

После некоторого исследования я обнаружил, что переменная, используемая в Python в конструкции типа foreach, является не ссылкой, а отдельной скалярной переменной, поэтому я не могу обновить свой контейнериспользуя это.Есть ли способ обновить контейнер, используя стиль foreach?

Вот код, который демонстрирует мой вопрос:

inputString = "   Type X Widgets  ,  25, 14.20 ,  Type Y Widgets , 4  , 1.12 "
inputList = inputString.split(',')
print(inputList) # Now I need to get rid of whitespace on the ends of each element

# The foreach-style does NOT update inputList
for element in inputList:
    element = element.strip()
    print(element, end=",") # element contains the stripped string as I wanted
print()
print(inputList) # the whitespace on the ends of the elements is still there

# The for-style with subscripts DOES update inputList
for i in range(len(inputList)):
    inputList[i] = inputList[i].strip()
    print(inputList[i], end=",") # inputList[i] contains the stripped string as I wanted
print()
print(inputList) # it finally contains the stripped strings with no whitespace on the ends

Вот вывод для выше:

['   Type X Widgets  ', '  25', ' 14.20 ', '  Type Y Widgets ', ' 4  ', ' 1.12 ']
Type X Widgets,25,14.20,Type Y Widgets,4,1.12,
['   Type X Widgets  ', '  25', ' 14.20 ', '  Type Y Widgets ', ' 4  ', ' 1.12 ']
Type X Widgets,25,14.20,Type Y Widgets,4,1.12,
['Type X Widgets', '25', '14.20', 'Type Y Widgets', '4', '1.12']

Первый цикл for не обновляет контейнер.Второй делает.В этом простом случае не имеет большого значения, что мне придется использовать подписки, но мне бы очень хотелось иметь возможность использовать стиль foreach для обновления более сложных типов контейнеров, когда подстрочный индекс просто не подходит.

Я могу сделать это в C#, и это очень мощный инструмент, используемый таким образом.Возможно ли это в Python, делая что-то в дополнение к тому, что я пробовал в первом цикле?(Если это так, я бы подумал, что это будет связано с использованием указателей. У Python есть даже указатели?)

Ответы [ 3 ]

0 голосов
/ 24 октября 2018

В этом конкретном случае вы не можете.Это потому, что вы переназначаете объект вместо новой ссылки.

В итерации типа "foreach", подобной этой:

for element in inputList:

Вы выполняете итерацию объект самого элемента в списке.Но в этом случае это str объект, который является неизменным.то есть, когда вы пытаетесь присвоить эту строку:

element = element.strip()

Вы переназначаете элемент с новым объектом из вырезанного содержимого оригинала.Поскольку это новый объект, он никак не связан с самим inputList.

Однако во втором примере вы сейчас перебираете список индексов на основе inputList:

for i in range(len(inputList)):
# range(len(inputList)) -> range(0, 6)

Когда вы просматриваете список, обратите внимание, что вы снова переназначаете определенный индекс inputList:

inputList[i] = inputList[i].strip()

Это присваивает объект new вернуться к inputList[i].Это уже не тот str объект, который у вас когда-то был в списке.

Сказав, что в других случаях использования "foreach", который вы ищете, прекрасно работает, какПока объект изменчив .Обратите внимание на следующий пример:

lst = [[] for _ in range(5)]
lst
# [[], [], [], [], []]
for i in lst:
    i.append('foo')

lst
# [['foo'], ['foo'], ['foo'], ['foo'], ['foo']]

Обратите внимание на разницу: i не переназначено , но напрямую изменено методом append().Чтобы доказать, что i является прямой ссылкой на объект согласно вашему ожиданию, если бы я сделал это после завершения итерации :

i.append('bar')
lst
# [['foo'], ['foo'], ['foo'], ['foo'], ['foo', 'bar']]

id(i)
# 61353816
id(lst[-1])
# 61353816

Посмотрите, как последний элемент lst теперь добавлен.Это потому, что i все еще сохраняет ссылку.id() также показывает окончательное доказательство того, что вы спрашиваете.

Если бы я написал такую ​​итерацию следующим образом:

for i in lst:
    i = ['foo']

lst
# [[], [], [], [], []]
id(i)
# 61354112 <-- different obj id
id(lst[-1])
# 61353816

Она больше не будет работать по той же причинетвой пример не сделал.Потому что i теперь переназначен новому объекту вместо прямой ссылки на объект в итерации.Обратите внимание на разницу в идентификаторе объекта.

0 голосов
/ 24 октября 2018

ННМ.В цикле for во время каждой итерации ваша переменная (в вашем случае element ) будет назначена копии следующего значения (объекта) в вашем списке, а не ссылки наэто значение (объект).(Что не совсем правильно, но вы знаете, что я пытаюсь сказать).Таким образом, чтобы решить ваш проект, вы можете сделать что-то вроде этого:

for element in inputList:
    inputList[inputList.index(element)] = element.strip()
print(inputList)

Обратите внимание, что это не будет работать, если в вашем списке дважды будет один и тот же элемент.

Надеюсьпомогли!

0 голосов
/ 24 октября 2018

Может быть, это не то, что вам нужно, но простой способ - создать новый список, например:

inputList = [
    element.strip()
    for element in inputList]

Это назначит новый список той же переменной, заменив старый (старый будет убран мусором через некоторое время после этого).

Недостатком является то, что это удваивает объем используемой памяти;как только вышеприведенное утверждение выполнено, старый список может быть собран сборщиком мусора, но при этом все равно будет всплеск использования памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...