Question

I was shocked when the following code did not do what I expected it to do:

lines_list = ['this is line 1\n', 'this is line 2\n', 'this is line 3\n']
for line in lines_list:
    line = line.strip()

In Perl or in Java, my usage works well. Python is the one with the unique behavior.

In Java this will work:

String[] lines = {"this is line 1\n", "this is line 2\n", "this is line 3\n"};
for (String line : lines) {
    line = line.trim();
}

In Perl this will work:

my @lines = ("this is line 1\n", "this is line 2\n", "this is line 3\n");
foreach my $line (@lines) {
    $line =~ s/\s+$//;
    $line =~ s/^\s+//;
}

I of course expected each item in the list to become "stripped", i.e. in this case, to be free of the trailing '\n' char, but it did not...

print lines_list

The output:

['this is line 1\n', 'this is line 2\n', 'this is line 3\n']

Is there an elegant way to change the list items during the for loop? I don't want to duplicate the list...

Was it helpful?

Solution

You can go through by index and modify in place that way

for i, _ in enumerate(lines_list):
    lines_list[i] = lines_list[i].strip()

though I think many would prefer the simplicity of duplicating the list if the list isn't so big that it causes an issue

lines_list = [line.strip() for line in lines_list]

The issue is using the = operator reassigns to the variable line, it doesn't do anything to affect the contents of the original string. New python programmers are equally as often surprised when:

for i in range(10):
    print(i)
    i += 1

prints the numbers 0,1,2,3,4,5,6,7,8,9. This occurs because the for loop reassigns i at the beginning of each iteration to the next element in the range. It's not exactly your problem, but it's similar.

Since you are reading lines out of a file, and stripping them afterwards, really what you should do is

with open(file_name) as f:
    lines_list = [line.strip() for line in f]

which reads and strips one line at a time, rather than reading everything first, then stripping the lines afterwards

OTHER TIPS

You did forget to assigned new value (stripped string) to something.

Another way, how to assign it to a list in shorter way is:

>>> lst = ['this is line 1\n', 'this is line 2\n', 'this is line 3\n']
>>> import string
>>> lst = map(string.strip, lst)
>>> lst
['this is line 1', 'this is line 2', 'this is line 3]

In your example, line is simply a variable. It is not connected to the list, where it might come from. Think of the problems, that would occur, if every variable modifies its origin!

In python, lists normally are not modified but a new one is created. Therefore there is something called list comprehension:

lines_list = [line.strip() for line in lines_list]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top