Free Python reference · JavaScript timeline
Python 3.6: Readable formatting and annotations
F-strings put values beside their labels, annotations document variables, and underscores make numeric literals easier to read.
Released · Editorial review October 25, 2026
Introduced in Python 3.6 · Syntax
F-strings: expressions inside text
Prefix a string with f to evaluate expressions inside braces. The text and the value it describes stay together, which is useful for labels and small reports. Formatting specifications follow a colon: .2f displays two digits after the decimal point.
The expression is evaluated when execution reaches the f-string. Changing a variable later does not rewrite a string you already created. Use doubled braces, {{ and }}, when you need literal braces.
The example formats the display without changing the stored numeric price. Use formatting at the presentation boundary; keep numbers as numbers while calculating.
Earlier approach
label = "{}: ${:.2f}".format(item, price)
Context fragment; read it with the example below.
Worked example
Minimum Python 3.6
item = "Notebook" price = 4.5 label = f"{item}: ${price:.2f}" price = 6 print(label) print(f"{{item}} means {item}")
Expected output
Notebook: $4.50
{item} means Notebook
Example checked with CPython 3.14.8, CPython 3.15.0, Pyodide Python 3.13.2.
Common mistake
Formatting a number produces text; do not feed a currency label back into arithmetic. Avoid putting long calculations or side effects inside braces.
Try it yourself
Change the first price to 4.567. Predict the label and explain why assigning price = 6 afterward does not alter it.
Read more: Python 3.6 release notes · PEP 498
Introduced in Python 3.6 · Typing
Variable annotations document intent
A variable annotation attaches a type expression to a name. It gives static analysis tools information without changing ordinary assignment. Python 3.6 added this syntax for variables; function annotations existed earlier.
A type checker can flag incompatible assignments before execution. The interpreter itself still accepts the later string assignment below. Choose a type checker in a real project if you want that contract checked.
An annotation alone, such as count: int, does not initialize a value. Reading an unassigned local still fails. Keep initialization and documentation as separate responsibilities.
Worked example
Minimum Python 3.6
count: int = 3 print(count) count = "three" # A type checker should flag this assignment. print(count)
Expected output
3
three
Example checked with CPython 3.14.8, CPython 3.15.0, Pyodide Python 3.13.2.
Common mistake
Annotations do not validate incoming JSON or convert strings to integers. Runtime checks are still needed at external-data boundaries.
Try it yourself
Remove the second assignment, then write a comment describing which values count should accept. What would a runtime validator need to check?
Read more: Python 3.6 release notes · PEP 526
Introduced in Python 3.6 · Syntax
Underscores in numeric literals
Underscores let you group digits in source code. They do not become part of the stored number and do not change its value. Grouping is useful for large limits and bit patterns that would otherwise be easy to misread.
Decimal digits can be grouped by thousands; binary digits can be grouped in nibbles. The separator is a readability convention rather than an instruction about the number base. Ordinary printing does not preserve the source spelling.
This feature applies to numeric literals, not arbitrary user text. Keep parsing and output formatting separate from how you write constants.
Worked example
Minimum Python 3.6
limit = 1_000_000 mask = 0b1111_0000 print(limit) print(mask) print(f"{limit:_}")
Expected output
1000000
240
1_000_000
Example checked with CPython 3.14.8, CPython 3.15.0, Pyodide Python 3.13.2.
Common mistake
A trailing underscore or two consecutive underscores are invalid numeric syntax. Use a format specifier if separators are needed in output.
Try it yourself
Rewrite 65535 in hexadecimal with an underscore between byte pairs, then confirm its decimal value.
Read more: Python 3.6 release notes · PEP 515
Recap
F-strings put values beside their labels, annotations document variables, and underscores make numeric literals easier to read. Prefer the clearest form that works on your project's supported Python versions.
Read the full Python 3.6 release notes →