Saklain55
Saklain55

Reputation: 31

Why does .format(function()) not work, but % prints the value?

Code that I wrote:

def ball(f):  
    py_ball = f * 5
    u_ball = py_ball / 10  
    return py_ball, u_ball
print("py ball: {}, u ball: {}".format(ball(100)))

When I use str.format, it throws an exception:

Traceback (most recent call last):
  File "rear.py", line 5, in 
    print("py ball: {}, u ball: {}".format(ball(100)))
IndexError: tuple index out of range

But if I use % formatting:

print("py ball: %d, u ball: %d" % ball(100))

it works just fine and produces:

py ball: 500, u ball: 50

Upvotes: 3

Views: 99

Answers (3)

Martijn Pieters
Martijn Pieters

Reputation: 1121594

str.format() takes separate arguments for each slot, while % accepts a tuple or a single value. ball() returns a tuple, and that's a single argument as far as str.format() is concerned. Because your template has 2 slots, there is an argument missing for that second slot.

You have two options: Either accept a single argument for .format() and use formatting instructions to extract the nested elements, or pass in the tuple as separate arguments.

The latter can be done with the *expr call notation:

print("py ball: {}, u ball: {}".format(*ball(100)))

but the formatting specification lets you also address tuple elements:

print("py ball: {0[0]}, u ball: {0[1]}".format(ball(100)))

I used explicit numbering here to indicate that just one argument is expected, in position 0; 0[0] takes the first element of the tuple, 0[1] takes the second.

Upvotes: 6

aghast
aghast

Reputation: 15300

The return value of ball() is a single value - a tuple.

When you call "...".format(ball(100)) you are passing that single value to a function that will eventually want two values.

When you call "..." % ball(100) you are supplying a tuple to the % operator, which expects a tuple!

Not surprisingly, it works in the second case and fails in the first case.

Try using the splat operator to flatten the tuple into the arguments of the call to .format, or try expanding the tuple yourself, or try using named parameter access in the .format call:

ball100 = ball(100)

"py ball: {}, u ball: {}".format(*ball100)   # splat! Flatten the tuple

"py ball: {}, u ball: {}".format(ball100[0], ball100[1]) # DIY

"py ball: {ball[0]}, u ball: {ball[1]}".format(ball=ball100) # named arg

Upvotes: 0

Błotosmętek
Błotosmętek

Reputation: 12927

Your format string requires two arguments to .format, but you provide only one (which is a two-element tuple, but it is still one argument). On the other hand, % operator requires a single tuple as its right-hand argument, so it is OK. You could unpack your tuple using prefix asterisk operator:

b = ball(100)
print("py ball: {}, u ball: {}".format(*b))

Upvotes: 0

Related Questions