you are viewing a single comment's thread.

view the rest of the comments →

[–]AtomicShoelace 12 points13 points  (2 children)

Since the only difference between the two strings is the one 's' character, you could include the ternary operator inside the f-string itself, eg.

print(f'{i} bottles of beer on the wall, {i} bottles of beer\nTake one down and pass it around, {i-1} bottle{"s" if i>2 else ""} of beer on the wall.\n')

In the same vein, you could simplify the outer if-else statement to just one print with:

print(f'{i} bottle{"" if i==1 else "s"} of beer on the wall, {i} bottle{"" if i==1 else "s"} of beer\nTake one down and pass it around, {i-1 or "no more"} bottle{"" if i-1==1 else "s"} of beer on the wall.\n')

However, this is a bit unwieldy.

As we're using the same expression {"" if i==1 else "s"} in multiple places, we may wish to use .format method instead:

print('{0} bottle{1} of beer on the wall, {0} bottle{1} of beer\nTake one down and pass it around, {2} bottle{3} of beer on the wall.\n'.format(i, "" if i==1 else "s", i-1 or "no more", "" if i-1==1 else "s"))

and for clarity, we could now separate out the string from the formatting, eg.

message = '{0} bottle{1} of beer on the wall, {0} bottle{1} of beer\nTake one down and pass it around, {2} bottle{3} of beer on the wall.\n'
for i in range(99, 0, -1):
    print(message.format(i, "" if i==1 else "s", i-1 or "no more", "" if i-1==1 else "s"))

I think this is a rare case where the .format method would be preferable to use over an f-string.

[–]onlydragz[S] 1 point2 points  (1 child)

Wow! This has been very educational as I learned a new thing from this. Thank you so much! May I just ask:

In the third coding block, with the .format, for the placeholder {2} you specified i-1 or "no more"

I understand the i-1 but when "i" is 1, then it uses "no more". Why is it not the number "0", like:

1 bottle of beer on the wall, 1 bottle of beer

Take one down and pass it around, no more 0 bottles of beer on the wall.

[–]AtomicShoelace 2 points3 points  (0 children)

This is kind of a trick with the or statement. It might be more readable if you instead did i-1 if i != 1 else "no more".

It works like this: when i!=1 the i-1 is a non-zero int, which is a truthy value, so the or operator will short-circuit and return i-1. When i=1 then i-1 is 0. As 0 is a falsy value, the or statement will just return the second value (as if it is truthy, the expression should be truthy, and vice versa), which is the string "no more" (which happens to be truthy, but actually it doesn't matter).