0

In a comment on this post, somebody dropped this line of code:

print("\n".join(f'{a:{a}<{a}}' for a in range(1,10)))
1
22
333
4444
55555
666666
7777777
88888888
999999999

And it looks like magic to me, can somebody explain to me why it works (more specifically f'{a:{a}<{a}}').

Benoît P
  • 3,179
  • 13
  • 31

2 Answers2

7

You can demistify the output if you substitute some things:

print("\n".join(f'{a:4<5}' for a in range(1,10)))

and read up on String format mini language:

It left aligns the value of a in 5 spaces using 4 as filler:

14444
24444
34444
44444
54444
64444
74444
84444
94444

Playing around with code is a good way to get what it does ...

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
3

It's quite simple if you visualize the iterations:

1           # f'{1:1<1}', means start with 1, left align with 1 spaces filled with 1
22          # f'{2:2<2}', means start with 2, left align with 2 spaces filled with 2
333         # f'{3:3<3}', means start with 3, left align with 3 spaces filled with 3
4444        # f'{4:4<4}', means start with 4, left align with 4 spaces filled with 4
55555       # f'{5:5<5}', means start with 5, left align with 5 spaces filled with 5
666666      # f'{6:6<6}', means start with 6, left align with 6 spaces filled with 6
7777777     # f'{7:7<7}', means start with 7, left align with 7 spaces filled with 7
88888888    # f'{8:8<8}', means start with 8, left align with 8 spaces filled with 8
999999999   # f'{9:9<9}', means start with 9, left align with 9 spaces filled with 9

You already know what the f-string f'{a:{a}<{a}' does - when given an {object} within the string it will replace with said object. In this case, a is range of 1 to 9.

Then all you need to understand is what {9:9<9} does. It's a string formatter as the documentation that the answer has provided:

'<' Forces the field to be left-aligned within the available space (this is the default for most objects).

The x<y portion signifies to left-align the text with a width of y spaces. For any unused space, pad it with character x. So you start with {9} as the first character, and for the rest of the 8 unused spaces, fill it with {9}. This is what {9:9<9} does.

Then you apply the same logic and see how each iteration came about.

More importantly, it should be noted that what feels like "magic" is often just a lack of understanding. Once you take the time to digest and understand the process, it becomes very disillusioning and you become enlightened.

r.ook
  • 13,466
  • 2
  • 22
  • 39
  • Thanks, in my head it would have printed `{1:False}` as I though it had to do with the comparison operator `<` – Benoît P Feb 12 '19 at 18:33
  • What's within the `{}` quote is interpreted as a string formatter. But to add to your example, you *could* add computation within it as well. e.g. `f'{32:0{"b" if cond else "x"}}'` will format `32` as bytes or hex depending on condition. What's within the immediate `{}` gets evaluated first, and so the outer-most `{}` is left alone to be a string formatter to be evaluated last... if it's a valid format. – r.ook Feb 12 '19 at 18:40
  • One day, I might actually use this... Thank you for the great explanation. – Benoît P Feb 12 '19 at 19:14