Let's see your function step by step:
def read_messages(file):
Function read_messages
takes a single parameter, file
; begin function.
message = []
Let variable message
be the empty list ([]
).
for line in file:
For each line in file
, let variable line
be such a line.
new_line = line.strip()
Let variable new_line
be the line
variable, with all whitespaces at the beginning and end of it stripped.
message.append(new_line)
Append new_line
to message
.
return message
Return variable message
; end function.
The algorithm is correct (why did you said otherwise?), but can be simplified, first of all, the pattern...
x = []
for ...:
something = ...
x.append(something)
doSomething(x) # Can be `return` too
Can be simplied to a list comprehension. List comprehensions are a means for constructing a list in a simple and easy to read expression, without doing all the hassle to create the list, adding to it, and returning it. According to the previous pattern, you can do something like...
doSomething([ something for ... ])
That's the same as the pattern above! Now, applied to your code:
return [ ??? for line in file ]
What should we put instead of ???
there? Well, you must put the code that calculates new_line
(line.strip()
) of course! That's because new_line
can be tought of as a synonym for line.strip()
, as line.strip()
has no side effects (doing line.strip()
will always give the same result regardless of the time at which it's called, given that line
is the same). So...
return [ line.strip() for line in file ]
You can use that, or if you don't want to lose the whitespace at the beginning, then...
return [ line.rstrip() for line in file ]
rstrip()
does the same as strip()
, except that it does not removes whitespace at the beginning of the string.
So, your function becomes...
def read_messages(file):
return [ line.rstrip() for line in file ]
That's all according to your requirements, but let's do a few more optimizations!
If any line is empty, or contains just whitespace, would you want that line to go into the list? I won't, at least. So how would you fix that? I would take the list comprehension, and filter out all the empty lines, or those made up of just whitespace. So, the thing becomes...
import string
def read_messages(file):
return filter(lambda x: not all(map(lambda y: y in string.whitespace, x)), [ line.rstrip() for line in file ])
Now, what's that? First of all, a lambda
is like a function that you can declare as an expression anywhere. The format is lambda parameters...: return_value
. Did you noticed that return_value
stuff? Well, it happens that lambdas can only contain a single expression, and they implicitly return that expression. So, for example, lambda x: x + 1
is a function that takes a single parameter x
and returns x + 1
.
Now, we have three new functions: map
, filter
, and all
:
map(f, list)
: Takes a function f
and calls f(x)
for each x
in list
, creating another list holding the result of that. It's equivalent to [ f(x) for x in list ]
.
filter(f, list)
: Takes a function f
and creates a new list out of list
. For any x
in list
, if f(x)
is True
, then x
goes into the new list. Otherwise, it is discarded. It's equivalent to [ x for x in list if f(x) ]
.
all(list)
: Takes a list and returns True
if all elements in the list are True
, False
otherwise.
Finally, string.whitespace
is a list of all whitespace characters.
So, this new construct can be said in Plain English? Of course!
Return a new list made up of each line in the file, with its trailing whitespace removed, if the line is not empty and not all characters in that line are whitespace characters.