Skip to main content
GameDev.net gamedev.net
🔒 Locked

Python: for loops

Started by Daniel Miller Oct 14, 2005 at 8:09 PM 16 replies 2.9k views
Original Post
Daniel Miller
Daniel Miller
In python, how do you assign to the members of a list in a for loop? For example:
for line in data:
    line = line.split()

That assigns line, but not the actual member of the list. How is this done?
GnuVince
GnuVince
# ugly, C way.for i in xrange(len(data)):  data = data.split()# I think this is more Pythonic, but I haven't used Python in a few yearsdata = [ line.split() for line in data ]
timmay314
timmay314
for i in range(len(data)):    data = 3


Edit: Do what GnuVince said
Oluseyi
Oluseyi
What's the value of line? That code should work just fine. Of course, I assume that data is an iterable object, like a file.
Daniel Miller
Daniel Miller
Quote:
Original post by Oluseyi
What's the value of line? That code should work just fine. Of course, I assume that data is an iterable object, like a file.


Line is a string. Data is a list assigned from a file's readlines() method.

Oluseyi
Oluseyi
Quote:
Original post by Daniel Miller
I was hoping for some way of making line an alias of the member of data.

Like I said, if data is an iterable object, that's exactly what happens:
>>> data = ['one and two', 'three and four', 'five and six', 'seven']>>> for line in data:...     line = data.split()...     print line['one', 'and', 'two']['three', 'and', 'four']['five', 'and', 'six']['seven']>>> data = file('datasource.txt') # datasource.txt contains the same data>>> for line in data:...     line = data.split()...     print line['one', 'and', 'two']['three', 'and', 'four']['five', 'and', 'six']['seven']>>> 
Fruny
Fruny
Oluseyi - he wants to propagate changes to line back into data.

The best way to do that would probably be:

data = [line.split() for line in data]

Or, if you don't want to get a new list but reuse the old one:

data[:] = [line.split() for line in data]

Alternatively, you could rely on enumerate
for index,line in enumerate(data):    data[index] = line.split()
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Daniel Miller
Daniel Miller
Quote:
Original post by Fruny
Oluseyi - he wants to propagate changes to line back into data.

The best way to do that would probably be:

data = [line.split() for line in data]

Or, if you don't want to get a new list but reuse the old one:

data[:] = [line.split() for line in data]

Alternatively, you could rely on enumerate
for index,line in enumerate(data):    data[index] = line.split()


Yes, I'll use this method. Thanks a lot to all 4 of you. :)
Oluseyi
Oluseyi
Quote:
Original post by Fruny
Oluseyi - he wants to propagate changes to line back into data.

Apparently, your time as King of the N00bs has served you well! [smile]

I had no clue that's what he wanted.
Redleaf
Redleaf
Departing slightly from the main topic, how would using a generator expression compare?

data = list(line.split() for line in data)
or
data[:] = list(line.split() for line in data)

In some profiling tests where I've compared them to list comprehensions, it seems the generator expressions are a little faster. The documentation also claims that generator expressions are more memory efficient. Is there any reason to use list comprehensions instead? (Sorry for the slight question hijack, but this is something I've been curious about.)
Fruny
Fruny
I must admit that I do not know the precise answer to that question. I believe I have read that the intent for future versions of python is to have list comprehensions built on generator expressions, making your version of the code strictly equivalent.

Are generators currently faster? It's very possible, otherwise they wouldn't make such plans. Are generators more memory efficient. Yes, definitely. A list will keep all of its elements alive. A generator only keeps track of the one object it is generating at any given moment.

Why are list comprehensions still used? Well, remember that generator expressions are new to the language. Backward compability may matter a lot, especially if a Python 2.3 interpreter has been embedded in, say, a game. People are also more familiar with them.

And finally, there is a practical difference between the two: loop comprehensions (currently) expose their loop variable, generator expressions do not. I'll grant you that this can be seen as a further flaw in list comprehensions, even though there have been hacks that take advantage of it.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Kylotan
Kylotan
Redleaf, although generator expressions may be slightly faster, if you immediately convert them to a list (as in your example) then there's little point using them. This will mean that you set up the generator mechanism only to make little use of it. And you won't save any memory because the only way generators save memory is by not forming the list in the first place. So all you've done is complicated the syntax a little. Where generator expressions come in handy is when you're performing some sort of sequential operation on it and don't need the intermediate list for anything. In your example, you could just use the return value from the generator expression and not converting it to a list, and it would probably suffice for anything, as long as you don't want to try sorting the list, using random access, etc.

By the way, there's no point using the slice syntax [:] in the example you give - you end up taking a copy then discarding the original. So the first syntax is sufficient.
Fruny
Fruny
Quote:
Original post by Kylotan
By the way, there's no point using the slice syntax [:] in the example you give - you end up taking a copy then discarding the original. So the first syntax is sufficient.


Depends on whether he's got references to the original list somewhere else.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Redleaf
Redleaf
All of that makes sense. Thank you both for the clarification.
Kylotan
Kylotan
Quote:
Original post by Fruny
Quote:
Original post by Kylotan
By the way, there's no point using the slice syntax [:] in the example you give - you end up taking a copy then discarding the original. So the first syntax is sufficient.


Depends on whether he's got references to the original list somewhere else.


The example I was referring to was this:
data[:] = list(line.split() for line in data)

So, the list has just been created in the right-hand-side of the expression from a generator expression - there is no pre-existing list for him to possibly have a reference to at that point.
Redleaf
Redleaf
What he meant was that if you had an original list with multiple references:
data = [1,2,3,4,5]
data2 = data

Then this line would cause changes in data to also be seen by data2:
data[:] = list(line.split() for line in data)
Kylotan
Kylotan
Ah, good point. Sorry Fruny! I hadn't thought of doing things that way; in Python it's usually best to learn to embrace returning things by value rather than modifying them in-place. :)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.