Back to articles list Articles
12 minutes read

Python’s String format() Cheat Sheet

Everything you need to know about formatting strings in Python and the Python formatting mini-language.

You may know all kinds of ways to manually manipulate strings in Python – maybe you learned from our Working with Strings in Python course (part of the Python Basics track). Today you will learn about how Python handles string formatting, or the art of combining a string with dynamic data in such a way that it is easily legible by either a human reader or an expecting machine. (Check out this article if you’ll also be manipulating strings in SQL.)

What is String Formatting in Python?

Working with strings is one of the first things any developer learns to do; as such, it seems as if it should be one of the simplest. After all, all the ubiquitous “Hello World!” really does is print one string:

>>> print("Hello world!")
Hello world!

Complications arise, however, when we need to introduce dynamic data – meaning data that may change over time or with each execution. Take, for instance, the code snippet below:

>>> print("John ordered a Pepperoni Pizza for $4.25 with a 15% tip")
John ordered a Pepperoni Pizza for $4.25 with a 15% tip

In this snippet, we are printing the details of an order in a pizza restaurant. The data here, however, is hardcoded. What happens when we need to read the customer’s name, their order, its price, and the tip amount from variables?

>>> print("customer_name ordered a order_name for price with a tip_percentage tip")
customer_name ordered a order_name for price with a tip_percentage tip

That clearly won’t do.

Before the introduction of Python 3, string formatting was mainly achieved through the % operator. Its usage primarily consisted of adding a C-style placeholder in the string where a variable should go and then linking to it by appending the variable references to the string using %. This is demonstrated below:

>>> print("Lorem %s dolor sit %s..." % ("ipsum", "amet"))
Lorem ipsum dolor sit amet...

This outdated method has been explicitly disavowed in the Python 3 documentation because it’s error-prone and outdated. We won’t be spending any more time talking about it – except to mention that it could be useful when dealing with older versions of Python. As of Python 3, string formatting is performed chiefly using the format() function, which belongs to the String class.

If any of the terms above (such as variable or function) are unfamiliar to you, please read Python Terms Beginners Should Know – Part 1 and Python Terms Beginners Should Know – Part 2 before continuing this article.

Introducing the String.format() Function

The String.format() function is a powerful and flexible string formatting tool introduced in Python 3. (It is also available in versions 2.7 and onward.) It essentially functions by linking placeholders marked by curly braces {} and the formatting data inside them to the arguments passed to the function.

The simplest way to use the format() function is to insert empty placeholders {} in the string, then pass the needed variables as arguments.

>>> print("Apples can be {}, {}, and {}.".format("red", "yellow", "green"))
Apples can be red, yellow, and green.

If you don’t want the order of the placeholders to be identical to the order of the arguments, you can insert indexed placeholders {n}, where n is the index number of the argument the placeholder is supposed to link to.

>>> print("Apples can be {1}, {2}, and {0} - yes, {0}!".format("red", "yellow", "green"))
Apples can be yellow, green, and red - yes, red!

Note that you can shuffle the order to be whatever you want, and you can even reuse the same argument twice.

Using positional linking, as shown above, is not recommended for formatting larger strings. The index numbers don’t have any intrinsic meaning and can easily get jumbled up when the code is updated. The alternative is to link to the arguments using a named placeholder, e.g. {arg_name}.

>>> print("The name's {last_name}, {first_name} {last_name}.".format(first_name="James", last_name="Bond"))
The name's Bond, James Bond.

This should be enough to insert the variables into a string, but what if you wanted more out of your formatting? Let's return to the pizza order snippet and format it using simple placeholders.

>>> print("{} ordered a {} for {} with a {} tip".format(customer_name, order_name, price, tip_percentage))
John ordered a Pepperoni Pizza for 4.25 with a 0.15 tip

The variables are printed in their simplest form, but what if we wanted to specify the price’s decimal digits? Maybe we need to ensure the resulting strings align nicely. We definitely need to ensure that the tip percentage, currently stored as a decimal, is output as a percentage. To do that (and more), we need to use formatting modifiers as part of the Python formatting mini-language.

Introduction to the Python Formatting Mini-Language

The Python formatting mini-language is a syntax that allows modifiers to be placed into a particular placeholder to give it additional meaning. This meaning can be anything from the character width of the field, the precision of decimal types, or the notation in which the numbers (if any) are represented.

The general syntax of a placeholder according to the Python format specification is shown below:


Each field enclosed by square brackets [] represents a modifier category. Only one modifier from each category may be present at one time. For example, we cannot use both the left-align modifier < and the right-align modifier > in a single field.

Moreover, the order of the modifiers is strictly defined. For instance, the placeholder {.2+} is invalid, as the .precision modifier (here, .2) should always come after the sign modifier(here, +). A valid placeholder would be {+.2}.

All modifiers are optional, which is why even the empty placeholder {} remains valid.  The following tables detail the proper syntax for each of the modifier categories mentioned above.

Fill modifier

Any characterPrefix to an align value – sets the character to fill the padding (if any).>>> print("{:~^10}".format("TEST"))
Use only with align.

Align modifiers

<Left-aligns the field.>>> print("{:~<10}".format("TEST"))
>Right-aligns the field.>>> print("{:~>10}".format("TEST"))
=Right-aligns the field and forces padding to be placed after the sign.>>> print("{:~=10}".format(-58))
Numeric types only. Use only with sign.
^Center-aligns the field.>>> print("{:~^10}".format("TEST"))
Numeric fields only.

Sign modifiers

+Places a sign for both positive and negative numbers.>>> print("{:+} {:+}".format(58, -58))
+58 -58
Numeric fields only.
-Places a sign for negative numbers only.>>> print("{:-} {:-}".format(58, -58))
58 -58
Numeric fields only.
An empty spacePlaces a leading space before positive numbers and a sign before negative numbers.>>> print("{: } {: }".format(58, -58))
58 -58
Numeric fields only.

# modifier

#Alternate-form modifier; adds a prefix to hexadecimal, decimal, and octal types.>>> print("{0:#b} {0:#o} {0:#x} {0:#X}".format(124))
0b1111100 0o174 0x7c 0X7C
Numeric fields only.

Width modifier

digit+Defines the minimum width of the field.>>> print("{:~^10}".format("TEST"))

Grouping modifiers

_Defines the underscore as a thousands separator.>>> print("{:_}".format(123456789))
>>> print("{:_x}".format(123456789))
Numeric fields only. For types b, o, x, and X, underscore will be inserted every 4 digits.
,Defines the comma as a thousands separator.>>> print("{:,}".format(123456789))
Numeric fields only.

Precision modifier

.digit+Defines decimal precision.>>> print("{:.3f}".format(5 / 3))
>>> print("{:.3g}".format(5 / 3))
>>> print("{:.3s}".format("TEST"))
Defines digits after the point for types f and F, total digits for types g and G, or maximum characters displayed for strings.

Type modifiers

bBinary format>>> print("{:b}".format(112))
cCharacter format>>> print("{:c}".format(112))
dInteger format>>> print("{:d}".format(112))
eScientific notation>>> print("{:e}".format(112))
EScientific notation with uppercase>>> print("{:E}".format(112))
fFixed-point notation>>> print("{:f}".format(123.456))
FFixed-point notation (uppercase)>>> print("{:F}".format(float("inf")))
gGeneral decimal format - fixed point for smaller numbers, scientific notation for larger numbers.>>> print("{:g}".format(123.456))
>>> print("{:g}".format(123456789.456))
GGeneral decimal format (uppercase)>>> print("{:G}".format(123.456))
>>> print("{:G}".format(123456789.456))
nNumber format>>> print("{:n}".format(123.456))
oOctal format>>> print("{:o}".format(58))
sString format>>> print("{:s}".format("Hello world!"))
Hello world!
xHex format (lowercase)>>> print("{:x}".format(58))
XHex format (uppercase)>>> print("{:X}".format(58))
%Percentage format>>> print("{:%}".format(0.25))

Python’s Formatting Mini-Language Syntax: The Details

Alignment, Fill, and Width Modifiers

These modifiers help us format unpredictable-length variables to fit a fixed width. This is particularly useful if you want the string output to look neat and be tabulation-friendly.

The width modifier defines the minimum total field width of a field, including any prefixes, separators, and other formatting characters.

The alignment modifier defines whether the value is

  • < Left-aligned. The default for string types. Similar to ljust().
  • > Right-aligned. The default for numeric types. Similar to rjust().
  • = Right-aligned except for the sign, which is left-aligned. Handles numbers in the same way as zfill().
  • ^ Center-aligned. Similar to center().

Finally, the fill modifier defines the character that will be used to fill the empty spaces (if any) left by the padding. Its default value is an empty space. The fill modifier should always be right behind the alignment modifier.

>>> print("{:~^10}".format("TEST"))
>>> print("{:~<10}".format("TEST"))
>>> print("{:~>10}".format("TEST"))
>>> print("{:~=10}".format(-58))

Sign Modifiers

These modifiers determine the sign used in numeric types:

  • + Places + before positive numbers and - before negative numbers.
  • - Places nothing before positive numbers and - before negative numbers. This is the default.
  • An empty space places a leading space before positive numbers and - before negative numbers.

These modifiers cannot be used with non-numeric types.

>>> print("{:+} {:+}".format(58, -58))
+58 -58
>>> print("{:-} {:-}".format(58, -58))
58 -58
>>> print("{: } {: }".format(58, -58))
 58 -58

Grouping Modifiers

In numeric types, these define the way digits will be grouped. The possible values are:

  • _ Inserts an underscore as a thousands separator. If used with types b, o, x, or X, inserts an underscore once every 4 digits.
  • , Inserts a comma as a thousands separator. If used with type n, inserts a locale-aware separator instead.
>>> print("{:_}".format(123456789))
>>> print("{:_x}".format(123456789))
>>> print("{:,}".format(123456789))

Precision Modifier

The precision modifier defines how many digits will be displayed in fields with decimal types.

For floating-point types f and F, it indicates the decimal digits displayed after the point.

For types g and G, it indicates the total digits to be displayed both before and after the point.

For the string type s it indicates the maximum number of characters displayed.

>>> print("{:.3f}".format(5 / 3))
>>> print("{:.3g}".format(5 / 3))
>>> print("{:.3s}".format("TEST"))

Type Modifiers

The type modifier assigned to a field determines the type that field should be treated as. This has ramifications on how the data presented and in how many of the other modifiers work.

Type modifiers can be divided in three main categories string types, integer types, and decimal types.

There is only one string type, s:

>>> print("{:s}".format("Hello world!"))
Hello world!

The integer types are:

  • b Outputs an integer in base 2 (binary).
  • o Outputs an integer in base 8 (octal).
  • d Outputs an integer in base 10 (decimal).
  • x Outputs an integer in base 16 (hexadecimal). Hex letters are lowercase.
  • X Outputs an integer in base 16 (hexadecimal). Hex letters are uppercase.
  • n Same as d, except that it uses a locale-aware character as a thousands separator.
>>> print("{0:b} {0:d} {0:x} {0:X} {0:n}".format(124))
1111100 124 7c 7C 124

Finally, the available decimal types are:

  • e Scientific notation.
  • E Same as e, except the separator character is uppercase.
  • f Fixed-point notation.
  • F Same as f, but nan and inf become NAN and INF.
  • g General format. Displays smaller numbers in fixed-point notation and larger numbers in scientific notation. This mechanism is described in more detail in the Python format specification.
  • G Same as g, but uppercase.
  • n Same as g, except that it uses a locale-aware character as a thousands separator.
  • % Multiplies the number by 100, displays it in fixed-point notation, and adds a percent sign at the end.
>>> print("{0:e} {0:E} {0:f} {0:F} {0:g} {0:G} {0:n} {0:%}".format(123456.789))1.234568e+05 1.234568E+05 123456.789000 123456.789000 123457 123457 123457 12345678.900000%

The Alternate-Form Modifier

The alternate-form modifier # impacts the presentation of numeric types. In integer types, it adds the prefix 0b, 0o, 0x, or 0X to binary, octal, hexadecimal, and capital-hexadecimal notations, respectively.

>>> print("{0:#b} {0:#o} {0:#x} {0:#X}".format(124))
0b1111100 0o174 0x7c 0X7C

Accessing Arguments' Attributes and Items

So far, we saw how to link placeholders directly to variables. We can also access a variable’s attributes and items from the formatted string itself, as demonstrated below:

>>> print("{0.x},{0.y}".format(point))
>>> print("{0[0]},{0[1]}".format((2, 5)))

The Pizza Example with Properly Formatted Strings

With the tools described above, we are now ready to entirely format the pizza order example from earlier. Here it is again as a reminder:

>>> print("{} ordered a {} for {} with a {} tip".format(customer_name, order_name, price, tip_percentage))
John ordered a Pepperoni Pizza for 4.25 with a 0.15 tip

Our goal is to create a format that will result in an attractive, tabulation-friendly output with even row lengths. We also want it to display numbers in their proper formats.

Let’s start with the name. If we assume a maximum name length of 10 characters, then we can use a combination of the width and alignment modifiers to ensure that variations in name length won’t result in uneven row lengths. We set a width of 10, an alignment of center, and a type of string using {:^10s}.

The same principle applies for the order name, except that we’ll increase the width. We set a width of 20, an alignment of center, and a type of string using {:^20s}.

The price is a little different. It’s going to be a decimal type, and we’ll always need precisely 2 decimal digits. We set a precision of 2 and a type of fixed-point using {:.2f}.

Finally, the tip is a percentage, internally stored as a floating point. We are not interested in any decimals beyond the whole percentage itself, meaning we want a precision of 0. We set a precision of 0 and a type of percentage using {:.0%}.

Putting all of this together results in:

>>> order_str = "{:^10s} ordered a {:^20s} for ${:.2f} with a {:.0%} tip"

And now to test it:

>>> print(order_str.format("John", "Pepperoni Pizza", 4.25, 0.15))
>>> print(order_str.format("Mike", "Margherita Pizza", 3.55, 0.25))
>>> print(order_str.format("Greg", "Large fries", 1, 0.1))

The results:

   John    ordered a   Pepperoni Pizza    for $4.25 with a 15% tip
   Mike    ordered a   Margherita Pizza   for $3.55 with a 25% tip
   Greg    ordered a     Large fries      for $1.00 with a 10% tip

Pretty good! Rows are even, dollars are dollars, percentages are percentages, and all with the right decimal spaces.

Learn More about Formatting Strings in Python

You now have a pretty good background on what it takes to format strings in Python. To learn more about properly displaying strings, you can read the Python Formatting Mini-Language documentation as well as  How to Pretty-Print Tables in Python and others available on