Reputation: 1011
Let's say I have this list and following code which formats the list into a nice readable format:
a = ['erin', 'david', 'chris', 'adam']
print('\n'.join('{}: {}'.format(i,j) for i,j in reversed(list(enumerate(a,1)))))
and the output is this:
4: adam
3: chris
2: david
1: erin
If I were to convert the above code into a for loop, I found that in order to get the same result as above, you have to delete the .join()
method.
The for loop would look like this:
for i, j in reversed(list(enumerate(a,1))):
print ('{}: {}'.format(i,j))
The output:
4: adam
3: chris
2: david
1: erin
To me, the for loop makes more sense, I just dont understand why in the list comprehension, I would need the join() method to get the same result.
Upvotes: 1
Views: 582
Reputation: 2973
Technically, you are using a generator expression, not a list comprehension.
The real important question (in my mind) is why do you need a join
in the first place, and the reason is that print
does not iterate over an iterable passed as an argument, it just calls the __str__
method to get a string representation of the object, and prints that. For a list
, the __str__
method produces a representation of the list that shows its elements, so it looks as if print
iterated over the list, when it actually didn't.
If you write out your generator expression explicitly:
>>> g = ('{}: {}'.format(i,j) for i,j in reversed(list(enumerate(a,1))))
and then try to print it, you will just see information about the object:
>>> print(g)
<generator object <genexpr> at 0x10fb929e8>
If you iterate over it you get a string for each element of your list a
:
>>> next(g)
'4: adam'
>>> next(g)
'3: chris'
>>> next(g)
'2: david'
>>> next(g)
'1: erin'
The '\n'.join
string method does iterate over the argument you pass to it, and concatenates each result into a string:
>>> g = ('{}: {}'.format(i,j) for i,j in reversed(list(enumerate(a,1))))
>>> '\n'.join(g)
'4: adam\n3: chris\n2: david\n1: erin'
When you use a for loop, you also iterate over the results of the generator expression, and print each one.
Upvotes: 2
Reputation: 8982
Without the join
you only have the generator expression:
>>> ('{}: {}'.format(i,j) for i,j in reversed(list(enumerate(a,1))))
<generator object <genexpr> at 0xb72736e4>
You can collect individual generated items in the list:
>>> list('{}: {}'.format(i,j) for i,j in reversed(list(enumerate(a,1))))
['4: adam', '3: chris', '2: david', '1: erin']
but this is not the required output yet.
You can use join
to create a single string:
>>> '\n'.join('{}: {}'.format(i,j) for i,j in reversed(list(enumerate(a,1))))
'4: adam\n3: chris\n2: david\n1: erin'
which, when printed, gives the required output:
>>> print('\n'.join('{}: {}'.format(i,j) for i,j in reversed(list(enumerate(a,1)))))
4: adam
3: chris
2: david
1: erin
Anyway, your "counterexample" with the old style for
loop is perhaps more appropriate in this specific case, depending on the surrounding code.
Upvotes: 1
Reputation: 3541
Your list comprehension is closer to an equivelant of this:
string_list = []
for i, j in reversed(list(enumerate(a,1))):
string_list.append('{}: {}'.format(i,j))
print('\n'.join(string_list))
I know you have used generator expressions instead of actual list comprehensions, but the point is you are creating a "list" of strings and then joining them into one big string separated by newlines and printing that out. However in your second example you are looping through each element, creating the string, and printing it out (with an implicit new-line character) in each iteration.
For an easier example, if you wanted to print out the names (in your list a
) you could do it in these two ways:
a = ['erin', 'david', 'chris', 'adam']
# "\n".join(a) => "erin\ndavid\nchris\nadam"
print("\n".join(a))
or:
a = ['erin', 'david', 'chris', 'adam']
for name in a:
print(name) # prints on a new line
Upvotes: 1
Reputation: 17704
List comprehensions are generally used when you want to create an output list using an iterator. For loops are used when you want to do something with an iterator, or sometimes when the logic is a bit too complicated to stuff into a list comprehension.
In your case, the reason you need the join function is because in the for loop, you are calling print once for each string. print adds a newline each time it prints a string. With the list comprehension, you build up the entire string to be printed, and then call print once. Since you only call print once, you need to add the newlines yourself, which is what the join does.
Upvotes: 1
Reputation: 1302
The join is simply putting a newline character \n
between the elements that your joining and then your print is writing that one long string
"4: adam\n3: chris\n2: david\n1: erin"
In the second approach the print
statement is handling adding the newline character.
Upvotes: 1