TL;DR:
Despite this being the currently accepted & highest voted answer, these methods from this answer and variations (1, 2) of it:
print(", ".join(flavours) + ".") # Peilonrayz
print(", ".join(flavours), end=".\n") # Maarten Fabré
print(f'{", ".join(flavors)}.') # Andy
are all faster than the solution originally proposed in this answer:
print(*flavours, sep=', ', end='.\n')
Original Answer, Plus Explanation & Timing Analysis:
Consider also:
flavours = ['chocolate', 'vanilla', 'caramel', 'strawberry', 'coffee']
print(*flavours, sep=', ', end='.\n')
This does not perform any unnecessary string concatenation, nor does it require a loop variable to test for the final index.
How does this work?
The print function takes a variable number of arguments, and so would be defined something like:
def print(*args, sep=' ', end='\n', file=sys.stdout, flush=False):
# ...
except it is a built-in function.
The *args
parameter consumes all of the unnamed arguments into one list for processing by the function, allowing the function to take a variable number of arguments.
In the statement,
print(*flavours, sep=', ', end='.\n')
The "splat operator" (*
) takes the iterable flavours
and expands it into a list of arguments for the function, allowing the caller to pass a variable number of arguments to a function, taken from the contents of a container (list, tuple, etc).
The Python interpreter could match the *flavours
splat operator with the *args
variable argument list of the print function, and simply pass the flavours
list into the args
.
But does it? I got worried. Perhaps, because a list is given, and the variable argument list (in CPython
) is passed as a tuple, the list actually must be copied. How much time does it take.
After creating a class Null
output stream, to speed up the printing, I began passing variable sized lists to the various answers, and profiling the results. While my solution is one of the least amounts of code, it turns out that @Peilonrayz's solution of ", ".join(flavours)
seems to be the fastest.
Using tuples or lists doesn't seem to affect the performance much, so any thought that splatting a tuple
instead of a list
, to be collected into a *args
variable argument tuple
may be optimized to a no-op, seems to have been squashed.
Since print
will automatically convert objects to strings for printing, the above will work for all object types in a list. The ", ".join(flavours)
will only work for strings; it would have to be modified to convert non-strings to strings to be truly equivalent:
print(", ".join(map(str, flavours)) + ".")
a, a, a,
for[a, a, a]
. \$\endgroup\$