Skip to main content
Direct future users to the better answer(s); added 127 characters in body
Source Link
AJNeufeld
  • 35.3k
  • 5
  • 41
  • 103

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:

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:

Added Andy's answer, added grid lines & axis titles
Source Link
AJNeufeld
  • 35.3k
  • 5
  • 41
  • 103

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.

profile resultsprofile results

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)) + ".\n"")

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.

profile results

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)) + ".\n")

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.

profile results

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)) + ".")
Updated profile plot - with less "peaks"
Source Link
AJNeufeld
  • 35.3k
  • 5
  • 41
  • 103

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.

profile resultsprofile results

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)) + ".\n")

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.

profile results

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)) + ".\n")

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.

profile results

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)) + ".\n")
print converts objects to strings, join does not.
Source Link
AJNeufeld
  • 35.3k
  • 5
  • 41
  • 103
Loading
Peilonrayz is actually 3 characters shorter - once you add the missing \n
Source Link
AJNeufeld
  • 35.3k
  • 5
  • 41
  • 103
Loading
Added list-tuple comparison
Source Link
AJNeufeld
  • 35.3k
  • 5
  • 41
  • 103
Loading
Added `*flavours` explanation, and profiling results
Source Link
AJNeufeld
  • 35.3k
  • 5
  • 41
  • 103
Loading
Source Link
AJNeufeld
  • 35.3k
  • 5
  • 41
  • 103
Loading