{"id":"formatting-widths","slug":"widths","title":"Widths and alignment","text":"Values of different lengths make ragged output. A table is easier to read when each column has its own width. In a format specifier, a number on its own is a **width**: the value takes at least that many characters, and spaces fill the rest:\n\n```python\nfruit = [\"fig\", \"banana\", \"kiwi\"]\nprices = [3, 12, 5]\nfor i in range(len(fruit)):\n    print(f\"{fruit[i]:8}|{prices[i]:4}|\")\n```\n\n```output\nfig     |   3|\nbanana  |  12|\nkiwi    |   5|\n```\n\nThe names take 8 characters and the prices 4. Strings are put at the left edge of their space, numbers at the right. That's the usual way: words line up at their start and numbers at their last digit.\n\n### Choosing the alignment\n\nA character before the width chooses the alignment: `<` for the left, `>` for the right and `^` for the middle:\n\n```python\nword = \"cat\"\nprint(f\"[{word:<7}]\")\nprint(f\"[{word:>7}]\")\nprint(f\"[{word:^7}]\")\n```\n\n```output\n[cat    ]\n[    cat]\n[  cat  ]\n```\n\nA width is the least space a value takes, not the most. A longer value isn't cut: `{\"elephant\":4}` is the whole `elephant`, and the column after it shifts. Choose widths for the longest value you expect.\n\n### Width and decimals together\n\nFor numbers with decimals, the width comes before the dot. `{price:7.2f}` shows the price with two decimals, in a space of 7 characters. That's what lines up the decimal points of a receipt:\n\n```python\nitems = [\"Coffee\", \"Croissant\", \"Water\"]\nprices = [3.5, 2.95, 1.2]\nfor i in range(len(items)):\n    print(f\"{items[i]:<12}{prices[i]:7.2f}\")\nprint(\"-\" * 19)\nprint(f\"{'Total':<12}{sum(prices):7.2f}\")\n```\n\n```output\nCoffee         3.50\nCroissant      2.95\nWater          1.20\n-------------------\nTotal          7.65\n```\n\nThe two widths add up to 19, the length of the dashed line. Inside an f-string in double quotes, a string in the braces is written in single quotes, like `'Total'`.\n","task":"Fill in the blanks so the program prints the names in a column of 10 characters, aligned to the left, and the points aligned to the right in a column of 4:\n\n```\nAda         12\nLinus        7\nGrace      105\n```\n","kind":"fill","seed":"names = [\"Ada\", \"Linus\", \"Grace\"]\npoints = [12, 7, 105]\nfor i in range(len(names)):\n    print(f\"{names[i]:[[<10‖10]]}{points[i]:[[>4‖4]]}\")\n","solution":"names = [\"Ada\", \"Linus\", \"Grace\"]\npoints = [12, 7, 105]\nfor i in range(len(names)):\n    print(f\"{names[i]:<10}{points[i]:>4}\")\n","hints":["A width is a number after the colon. `<` aligns to the left and `>` to the right.","The names take `<10` and the points `>4`. (Strings go to the left and numbers to the right anyway, so `10` and `4` work too.)"],"tests":[{"name":"Output","stdin":"","expect":"Ada         12\nLinus        7\nGrace      105","hidden":false}],"require":[],"forbid":[],"more":[{"task":"Write the function `print_scores(names: list, scores: list)`, which prints a table of names and scores. Each name is in a column of 10 characters, aligned to the left, and each score is in a column of 6, aligned to the right, with one decimal. The lists are equally long, and the score at an index belongs to the name at the same index. For example, `print_scores([\"Mia\", \"Noah\"], [9.24, 10])` prints:\n\n```\nMia          9.2\nNoah        10.0\n```\n","kind":"code","seed":"def print_scores(names: list, scores: list):\n    pass\n\n\nif __name__ == \"__main__\":\n    print_scores([\"Mia\", \"Noah\"], [9.24, 10])\n","solution":"def print_scores(names: list, scores: list):\n    for i in range(len(names)):\n        print(f\"{names[i]:<10}{scores[i]:6.1f}\")\n\n\nif __name__ == \"__main__\":\n    print_scores([\"Mia\", \"Noah\"], [9.24, 10])\n","hints":["Go through the indexes with `range(len(names))`, so you can use `names[i]` and `scores[i]` together.","The name is `{names[i]:<10}`. The score needs a width and decimals: `{scores[i]:6.1f}`.","Don't put a space between the two columns: the widths already give the spacing."],"tests":[{"name":"print_scores([\"Mia\", \"Noah\"], [9.24, 10])","stdin":"","call":"print_scores([\"Mia\", \"Noah\"], [9.24, 10])\n","expect":"Mia          9.2\nNoah        10.0","hidden":false},{"name":"print_scores([\"Olivia\", \"Liam\", \"Emma\"], [8.5, 7.66, 9.96])","stdin":"","call":"print_scores([\"Olivia\", \"Liam\", \"Emma\"], [8.5, 7.66, 9.96])\n","expect":"Olivia       8.5\nLiam         7.7\nEmma        10.0","hidden":true},{"name":"print_scores([\"Sam\"], [100])","stdin":"","call":"print_scores([\"Sam\"], [100])\n","expect":"Sam        100.0","hidden":true}],"require":[],"forbid":[]},{"task":"What does this program print? Type each line it prints. The brackets show where each value starts and ends.\n","kind":"predict","seed":"word = \"ok\"\nnumber = 42\nprint(f\"[{word:4}]\")\nprint(f\"[{number:4}]\")\nprint(f\"[{word:>4}]\")\nprint(f\"[{number:<4}]\")\nprint(f\"[{number:1}]\")\n","solution":"word = \"ok\"\nnumber = 42\nprint(f\"[{word:4}]\")\nprint(f\"[{number:4}]\")\nprint(f\"[{word:>4}]\")\nprint(f\"[{number:<4}]\")\nprint(f\"[{number:1}]\")\n","hints":["With a width alone, a string goes to the left of its space and a number to the right.","`>` and `<` change the alignment: the string goes right and the number left.","A width smaller than the value doesn't cut it: the whole number is shown."],"tests":[{"name":"Output","stdin":"","expect":"[ok  ]\n[  42]\n[  ok]\n[42  ]\n[42]","hidden":false}],"require":[],"forbid":[],"lines":["[ok  ]","[  42]","[  ok]","[42  ]","[42]"]}]}