1

I have a list mylist = [1, 2, 3] and a number n which I want to print in a specific way:

{n} {book or books} read ok: {mylist elements one by one separated by commas)

for example:

1 book read ok: 1 , 2, 3

2 books read ok: 1 , 2, 3

The decision of printing book or books depends on n, i.e. if n is 1 then print book, else print books. The code for achieving that is:

print("{:s}", "book" if n == 1 else "books")

For printing the elements of the list the code is:

print(*mylist, sep=' , ')

But, I am having problems trying to combine all of this into the desired output with including .format for displaying n as described above.

Here is what I have tried so far:

print("{0} {:s} read ok: {1}".format(n, *mylist, sep=' , '), "book" if n == 1 else "books")

which gives ValueError: cannot switch from manual field specification to automatic field numbering

2
  • 1
    And what don't you understand about that message? You have three placeholders, {0}, {:s} and {1}, and Python can't figure out what you expected to go where! Commented Jun 16, 2016 at 11:39
  • @jonrsharpe Well, however on-point and informative the error message was, I did not know how to overcome it and achieve my goal. Hence, my question. Commented Jun 16, 2016 at 12:12

1 Answer 1

2

Dissected call to print():

print(
    "{0} {:s} read ok: {1}".format(
        n,  # 1st argument to format
        *mylist,  # mylist unpacked as positional arguments to format
        sep=' , '  # a keyword argument to format
    ),  # Formatted string, the 1st argument to print
    "book" if n == 1 else "books"  # 2nd argument to print
)

The error is a result of mixing manual and automatic field specifications, as it very clearly states. Don't mix manual ("{0}" etc). with automatic ("{}"). In your string you have 0, automatic and 1. There's no sane way to decide which positional argument the automatic should be, and so the error is raised.

From the documentation:

If the numerical arg_names in a format string are 0, 1, 2, ... in sequence, they can all be omitted (not just some)

A working print in this case could be:

print("{} {} read ok: {}".format(
    n,
    "book" if n == 1 else "books",
    ', '.join(str(i) for i in mylist)
))

The format string is equal to:

"{0} {1} read ok: {2}"
Sign up to request clarification or add additional context in comments.

2 Comments

Quick follow-up: could you briefly explain why the {:s} is not needed? Confused how it did work previously in isolation with that :s
Depends on your isolated test. The part after the colon is the format specification, e.g. in "{:s}" it is the s. s is the default presentation type for string types and may be omitted. Hence it equals "{}" for string types. For integers the default presentation type is d, for example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.