Latest in branch 3.6
3.6.15
Released 04 Sep 2021
(4 years ago)
SoftwarePython
Version3.6
Status
End of life
Initial release3.6.0
22 Dec 2016
(9 years ago)
Latest release3.6.15
04 Sep 2021
(4 years ago)
End of life23 Dec 2021
(Ended 4 years, 5 months ago)
Source codehttps://github.com/python/cpython/tree/v3.6.15
Documentationhttps://docs.python.org/release/3.6.15/
Downloadhttps://www.python.org/downloads/release/python-3615/
Python 3.6 ReleasesView full list

What Is New in Python 3.6

Python 3.6 was released on December 22, 2016. The standout additions are formatted string literals (f-strings), the secrets module for cryptographically secure random data, underscores in numeric literals, variable annotations, and the async/await becoming reserved syntax. CPython's dictionary implementation was also completely reworked, delivering a compact and faster dict that preserves insertion order as an implementation detail.

Category Change PEP / Reference
New Syntax Formatted string literals -- f-strings PEP 498
New Syntax Variable annotations (x: int = 5) PEP 526
New Syntax Underscores in numeric literals (1_000_000) PEP 515
New Syntax Asynchronous generators and comprehensions PEP 525, PEP 530
New Modules secrets -- cryptographically secure random tokens PEP 506
Standard Library typing enhancements: ClassVar, NewType, TYPE_CHECKING PEP 526, PEP 544
Performance CPython dict reimplemented -- 20-25% memory reduction, insertion-order preserved --
Performance Faster isinstance() checks for classes with __instancecheck__ --
Interpreter Customization of class creation without metaclass: __init_subclass__ PEP 487
Interpreter Descriptor protocol extended: __set_name__ PEP 487
asyncio New async/await reserved keywords; async generators and comprehensions PEP 525, PEP 530
Deprecated Misuse of StopIteration inside generators now raises RuntimeError PEP 479

What Are the Key Language Features in Python 3.6?

Formatted String Literals -- f-strings (PEP 498)

F-strings are string literals prefixed with f or F. Expressions inside {} are evaluated at runtime and formatted into the string. They are the fastest string formatting option in Python -- faster than % formatting, .format(), and str.join() in most benchmarks.

name = "Alice"
age = 30
print(f"Name: {name}, Age: {age}")         # Name: Alice, Age: 30
print(f"Next year: {age + 1}")             # Next year: 31
print(f"{'hello':>10}")                   # right-align with width 10
print(f"{3.14159:.2f}")                   # 3.14

F-strings also support nested expressions, lambda functions (wrapped in parens), and multi-line formatting. They replaced the need for "Hello %s" % name and "Hello {}".format(name) in virtually all new code.

Variable Annotations (PEP 526)

Variables can now be annotated at the module, class, and function level without assignment. Annotations are stored in __annotations__ on the enclosing scope but are not enforced at runtime.

count: int = 0
items: list[str] = []

class Config:
    host: str
    port: int = 8080
    debug: bool

Underscores in Numeric Literals (PEP 515)

Underscores can be placed freely in numeric literals for readability. They are ignored by the parser -- only the value matters.

one_million = 1_000_000
hex_addr    = 0xDEAD_BEEF
pi_approx   = 3.141_592_653
binary_mask = 0b1111_0000

New Standard Library: The secrets Module (PEP 506)

The secrets module provides functions for generating cryptographically strong random data suitable for tokens, passwords, and similar security-sensitive use cases. It is backed by the OS random source and is explicitly not intended for simulations or games -- that is what random is for.

import secrets

token = secrets.token_hex(32)      # 64-char hex string
url_token = secrets.token_urlsafe(16)  # URL-safe base64 token
pin = secrets.randbelow(10 ** 6)   # 0 to 999999

Before secrets, many developers incorrectly used random.random() or random.choice() for security tokens -- those are seeded with a predictable value and are not suitable for this purpose.

Async Generators and Comprehensions (PEP 525, PEP 530)

Python 3.6 extends async support to generators and comprehensions. An async def function can now contain yield, creating an async generator that works with async for. Async comprehensions allow await expressions inside list, set, dict, and generator expressions.

async def fetch_pages(urls):
    async for url in urls:
        page = await fetch(url)
        yield page

# Async comprehension
results = [r async for r in fetch_pages(url_list)]

CPython Dictionary Overhaul

CPython 3.6 ships a completely reworked dict implementation by Inada Naoki (based on a design by Raymond Hettinger). The new structure uses a compact array plus a separate index table, reducing memory usage by 20-25% for typical dictionaries. As a side effect of the implementation, dictionaries maintain insertion order -- though this was documented only as a CPython implementation detail in 3.6 and became a language guarantee in 3.7.

FAQ

Are f-strings faster than .format() and why?
Yes, measurably. F-strings are compiled to bytecode that evaluates expressions directly, whereas .format() parses the template string at runtime. In micro-benchmarks, f-strings are roughly 2x faster than str.format() and about 30% faster than % formatting. For tight loops doing lots of string construction, this is meaningful.

Do variable annotations in Python 3.6 enforce types at runtime?
No. Annotations are purely metadata -- they are stored in __annotations__ but the interpreter does not check or enforce them. Type checkers like mypy and pyright read annotations statically. For runtime enforcement, you need a library like Pydantic or beartype.

Can I use async generators with asyncio.gather()?
No directly. asyncio.gather() takes awaitables (coroutines, tasks, futures), not async generators. To consume an async generator in parallel you'd iterate it explicitly and dispatch with asyncio.create_task(). The async for loop consumes it sequentially.

Is dict insertion order preserved in Python 3.6 for all implementations?
Only as a CPython implementation detail in 3.6. Other implementations (PyPy, Jython, MicroPython) were not required to follow it. The insertion-order guarantee became part of the Python language specification in 3.7, covering all conforming implementations.

What replaced the secrets module before Python 3.6?
The correct approach was os.urandom() for raw bytes, or constructing tokens manually using os.urandom() combined with base64.urlsafe_b64encode(). The secrets module wraps this correctly and provides a clean, auditable API so developers don't have to remember the right combination themselves.

Releases In Branch 3.6

VersionRelease date
3.6.1504 Sep 2021
(4 years ago)
3.6.1428 Jun 2021
(4 years ago)
3.6.1316 Feb 2021
(5 years ago)
3.6.1215 Aug 2020
(5 years ago)
3.6.1127 Jun 2020
(5 years ago)
3.6.11rc117 Jun 2020
(5 years ago)
3.6.1018 Dec 2019
(6 years ago)
3.6.10rc111 Dec 2019
(6 years ago)
3.6.902 Jul 2019
(6 years ago)
3.6.9rc119 Jun 2019
(6 years ago)
3.6.823 Dec 2018
(7 years ago)
3.6.8rc111 Dec 2018
(7 years ago)
3.6.720 Oct 2018
(7 years ago)
3.6.7rc213 Oct 2018
(7 years ago)
3.6.7rc126 Sep 2018
(7 years ago)
3.6.626 Jun 2018
(7 years ago)
3.6.6rc112 Jun 2018
(7 years ago)
3.6.528 Mar 2018
(8 years ago)
3.6.5rc114 Mar 2018
(8 years ago)
3.6.419 Dec 2017
(8 years ago)
3.6.4rc105 Dec 2017
(8 years ago)
3.6.303 Oct 2017
(8 years ago)
3.6.3rc119 Sep 2017
(8 years ago)
3.6.208 Jul 2017
(8 years ago)
3.6.2rc207 Jul 2017
(8 years ago)
3.6.2rc117 Jun 2017
(8 years ago)
3.6.121 Mar 2017
(9 years ago)
3.6.1rc104 Mar 2017
(9 years ago)
3.6.022 Dec 2016
(9 years ago)
3.6.0rc216 Dec 2016
(9 years ago)
3.6.0rc107 Dec 2016
(9 years ago)
3.6.0b422 Nov 2016
(9 years ago)
3.6.0b301 Nov 2016
(9 years ago)
3.6.0b210 Oct 2016
(9 years ago)
3.6.0b112 Sep 2016
(9 years ago)
3.6.0a415 Aug 2016
(9 years ago)
3.6.0a311 Jul 2016
(9 years ago)
3.6.0a213 Jun 2016
(9 years ago)
3.6.0a116 May 2016
(10 years ago)