10

Put simply, why do I get the following error?

>>> yes = True
>>> 'no [{0}] yes [{1}]'.format((" ", "x") if yes else ("x", " "))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: tuple index out of range

I use python 2.6.

Burger King
  • 2,945
  • 3
  • 20
  • 45
  • 1
    You actually provide a single formatting argument. To get two values, which translates to unpacking a tuple you should use splat operator. Please refer to http://stackoverflow.com/questions/36901/what-does-double-star-and-star-do-for-python-parameters . – Łukasz Rogalski May 12 '15 at 08:23
  • you might like to consider `'no [{no}] yes [{yes}]'.format(**{'no': novalue, 'yes': yesvalue})` – wim May 12 '15 at 08:24

3 Answers3

14

☞ Indexing option:

When accessing arguments’ items in format string, you should use index to call the value:

yes = True
print 'no [{0[0]}] yes [{0[1]}]'.format((" ", "x") if yes else ("x", " "))

{0[0]} in format string equals (" ", "x")[0] in calling index of tulple

{0[1]} in format string equals (" ", "x")[1] in calling index of tulple


* operator option:

or you can use * operator to unpacking argument tuple.

yes = True
print 'no [{0}] yes [{1}]'.format(*(" ", "x") if yes else ("x", " "))

When invoking * operator, 'no [{0}] yes [{1}]'.format(*(" ", "x") if yes else ("x", " ")) equals 'no [{0}] yes [{1}]'.format(" ", "x") if if statement is True


** operator option (It's extra method when your var is dict):

yes = True
print 'no [{no}] yes [{yes}]'.format(**{"no":" ", "yes":"x"} if yes else {"no":"x", "yes":" "})
Burger King
  • 2,945
  • 3
  • 20
  • 45
8

Use the * operator, which takes an iterable of parameters and supplies each one as a positional argument to the function:

In [3]: 'no [{0}] yes [{1}]'.format(*(" ", "x") if yes else ("x", " "))
Out[3]: 'no [ ] yes [x]'
Patrick Collins
  • 10,306
  • 5
  • 30
  • 69
  • The problem is that in your original code, you give a tuple as the first argument instead of two arguments (which the string to be format requires). The `*` operator expands your tuple to be two arguments instead of one. – wonderb0lt May 12 '15 at 08:20
  • @wonderb0lt I followed the structure suggested by the OP's format string rather than his question, which I suspect is what he really wants to do. IMO, `{0[0]}..{0{1}}` is much uglier, and unnecessary. – Patrick Collins May 12 '15 at 08:23
  • @PatrickCollins Sure, I meant my comment as a side note for OP to understand what is happening here (before your answer included that information) :) – wonderb0lt May 12 '15 at 08:28
6

The issue here is that you are only providing one argument to string.format(): a tuple. When you use {0} and {1}, you are referring to the 0th and 1st arguments passed to string.format(). Since there isn't actually a 1st argument, you get an error.

The * operator, as suggested by @Patrick Collins, works because it unpacks the arguments in tuple, turning them into individual variables. It's as if you called string.format(" ", "x") (or the other way around)

The indexing option suggested by @Tony Yang works because it refers to the individual elements of the one tuple passed to format(), rather than attempting to refer to a second argument.

seaotternerd
  • 6,298
  • 2
  • 47
  • 58