Printf-style String Formatting

Python has two styles of string formatting. In this video, I am going to cover the C-Style or Printf-style formatting. In the next video, I’ll go over the new-style formatting.

Formatting Operator

The % operator, applied to numbers, means “modulo” – the remainder after division. When applied to strings or bytes, it means to perform the printf-style formatting with the value that follows.

The value that follows may be:

  • A tuple of values.

  • A dictionary.

  • A single value.

The allowable types following the % operator depend on what type of % escapes exist in the string or byte.

  • If mapping keys are used, then it requires a dictionary.

  • If multiple substitutions are used, then a tuple with that many values is required.

  • If only one substitution is used, then a single value or a tuple with a single value is required.

Typically, the %-escapes are very simple: %s, %d, %f, etc… and most of the time this is all you need. However, there are a number of options that allow you to get creative with how you substitute values in.

  • You may optionally name the substitutions by following the % with (key name). If you are formatting a string, then the key will be a string. If you are formatting a bytes object, then the key will be a bytes object. Note that either ALL of the substitutions must have a key name or none of them can have it. You’ll get a TypeError if you are not consistent in either using key names or not.

  • Following the name, you may have one or more conversion flags, which have a special meaning depending on the type of the substitition, These are #, 0, -, space, and +. - # means to use the alternate form. Each type has its own alternate

    form.

    • 0 will pad numbers with zeroes to fill up the space.

    • - will format the substitution to the left rather than the right, leaving space at the end to fill up the minimum space.

    • space will leave a space for positive numbers, so that it aligns with negative numbers.

    • + will force the + sign to appear for positive numbers. (Negative numbers will always have a -.)

  • After the optional conversion flags, you may specify how much space, minimum, to allocate for the value when it is substituted in. If you use a *, then it will read in the next value to determine how much space to leave.

  • After the optional minimum field width, you can specify the precision. This is done with a . followed by a number. If you use a * for the number, then the precision is read in from the next value in the tuple.

  • After the precision, you can include a “length modifier”, which is h, l, or L. This means nothing to Python, but it is used in C/C++ to handle “long” integers or floats.

  • Finally, you must specify a conversion type. One of the following letters must be used:

    • d, i, u: Signed decimal integer. (u typically means unsigned, but Python ignores this. Everything is signed.)

    • o: Signed octal integer. With the alternate form #, prepends a 0o.

    • x: Lower-case hexadecimal. With the alternate form #, prepends a 0x.

    • X: Upper-case hexadecimal. With the alternate form #, prepends a 0X.

    • e: Lower-case floating point exponential form. The alternate form # always contains a decimal point. The precision describes how many digits after the decimal point, and defaults to 0.

    • E: Same for e but uses an upper-case E.

    • f of F: FLoating-point decimal format. It will not use the e form. If not, then it uses e. Alternate form forces a decimal point. Precision describes how many digits after the decimal point to include.

    • g: Uses e if the exponent is less than -4 or not less than the precision, uses f otherwise. Alternate form always includes the decimal. Trailing zeroes are also not removed. The precision determines the number of significant digits to use.

    • G: Same as g but capital E when needed.

    • c: Single character.

    • r: repr(value). Precision truncates.

    • s: str(value). Precision truncates.

    • a: ascii(value). Precision truncates.

Integers

Let’s walk through some practical examples.

Suppose we want to format some integers, This is rather simple:

>>> "%d %d %d" % (1, -500, 700000)
'1 -500 700000'

If we want to get them to align, we’ll need to set a minimum space:

>>> "|%10d|%10d|%10d|" % (1, -500, 700000)
'|         1|      -500|    700000|'

If a number were to exceed those bounds, that would be bad and throw off the formatting.

We can force the positive sign to appear:

>>> "|%+10d|%+10d|%+10d|" % (1, -500, 700000)
'|        +1|      -500|   +700000|'

We can pad with zeros:

>>> "|%0+10d|%0+10d|%0+10d|" % (1, -500, 700000)
'|+000000001|-000000500|+000700000|'

Or left align:

>>> "|%-+10d|%-+10d|%-+10d|" % (1, -500, 700000)
'|+1        |-500      |+700000   |'

Making room for the negative signs:

>>> "|%- 10d|%- 10d|%- 10d|" % (1, -500, 700000)
'| 1        |-500      | 700000   |'

We can show hexadecimal numbers:

>>> "|%#10x|%#10x|%#10x|" % (1, -500, 700000)
'|       0x1|    -0x1f4|   0xaae60|'

Pad them with zeroes:

>>> "|%#010x|%#010x|%#010x|" % (1, -500, 700000)
'|0x00000001|-0x00001f4|0x000aae60|'

Leave room for minus signs:

>>> "|%#0 10x|%#0 10x|%#0 10x|" % (1, -500, 700000)
'| 0x0000001|-0x00001f4| 0x00aae60|'

And you can do the same for octal!

Floats

Formatting floats depends on how big or small your numbers are.

  • For “regular” numbers, %f is probably fine. %10.3f will give you 10 total spaces, 3 of them after the decimal point.

  • For “scientific” numbers, that may vary by a large amount, either use %e or %g. %e always shows the e, while g will avoid it if it can. Note that the precision is the number of significant figures, so if you’re really doing science, %g is what you’re looking for.