Stable Release in branch 3.8
3.8.20
Released 06 Sep 2024
(1 year ago)
SoftwarePython
Version3.8
Status
End of life
Initial release3.8.0
14 Oct 2019
(6 years ago)
Latest release3.8.20
06 Sep 2024
(1 year ago)
End of life14 Oct 2024
(Ended 1 year ago)
Source codehttps://github.com/python/cpython/tree/v3.8.20
Documentationhttps://docs.python.org/release/3.8.20/
Downloadhttps://www.python.org/downloads/release/python-3820/
Python 3.8 ReleasesView full list

What Is New in Python 3.8

Python 3.8 was released on October 14, 2019. The most visible addition is the walrus operator := (assignment expressions). Beyond that, positional-only parameters, f-string debugging with =, shared-memory multiprocessing, and a fast vectorcall protocol for CPython all landed in this release.

Category Change PEP / Reference
New Syntax Assignment expressions -- the walrus operator := PEP 572
New Syntax Positional-only parameters via / in function signatures PEP 570
New Syntax f-string = specifier for self-documenting expressions --
Performance Vectorcall -- fast call protocol for CPython extension types PEP 590
Standard Library multiprocessing.shared_memory -- shared memory between processes PEP 567
Standard Library Pickle Protocol 5 with out-of-band data buffers PEP 574
Security Runtime audit hooks for monitoring sensitive operations PEP 578
Typing Final, Literal, TypedDict added to typing PEP 591, 586, 589
Interpreter Richer Python initialization configuration C API PEP 587
Performance LOAD_GLOBAL opcode significantly faster --
Build Debug builds share ABI with release builds -- no more separate debug extensions --
Performance Parallel filesystem cache for __pycache__ via PYTHONPYCACHEPREFIX --

What Are the Key Language Changes in Python 3.8?

Assignment Expressions -- the Walrus Operator (PEP 572)

The := operator assigns a value to a variable inside an expression. This cuts duplicated evaluation in loops, comprehensions, and conditionals.

# Avoid calling len() twice
if (n := len(data)) > 10:
    print(f"Too long: {n} items")

# Read until empty block
while chunk := f.read(8192):
    process(chunk)

# Filter and compute in one pass
results = [y for x in data if (y := transform(x)) is not None]

In practice, the walrus operator is most useful when a computed value is needed both in the condition and the body. Keep usage deliberate -- overuse hurts readability more than it helps.

Positional-Only Parameters (PEP 570)

The / separator in a function signature marks all preceding parameters as positional-only -- callers cannot pass them by keyword name. This mirrors how many built-in functions already behave.

def hypot(x, y, /, *, precision=10):
    # x and y must be positional; precision must be keyword
    ...

hypot(3, 4)                    # OK
hypot(x=3, y=4)                # TypeError
hypot(3, 4, precision=5)       # OK

This matters for API design: renaming x or y becomes a non-breaking change, and it prevents fragile code that passes positional args by name.

f-string = Specifier for Debugging

Adding = to an f-string expression prints both the expression text and its value. This replaces the common pattern of writing print(f"x = {x}") manually.

x = 42
theta = 2.5

print(f"{x=}")        # x=42
print(f"{theta=:.2f}")  # theta=2.50
print(f"{x + 1 = }")  # x + 1 = 43

Standard Library Additions in Python 3.8

Shared Memory for Multiprocessing

The new multiprocessing.shared_memory.SharedMemory class lets multiple Python processes share a block of memory directly, bypassing serialization entirely. This is a significant throughput win for high-volume inter-process data exchange like image buffers or large arrays.

from multiprocessing import shared_memory
import numpy as np

shm = shared_memory.SharedMemory(create=True, size=1024)
arr = np.ndarray((128,), dtype=np.float64, buffer=shm.buf)
arr[:] = 0.0  # write directly into shared memory

Pickle Protocol 5 (PEP 574)

Protocol 5 adds out-of-band buffer support, allowing the data payload to be transferred separately from the pickle stream. This is particularly relevant for multiprocessing and distributed frameworks that want to avoid copying large buffers like NumPy arrays into the pickle bytestream.

typing Additions: Final, Literal, TypedDict

  • Final -- marks a variable or attribute as non-reassignable. Type checkers enforce this at analysis time.
  • Literal -- restricts a parameter to specific constant values: def set_level(level: Literal["debug", "info", "error"]) -> None
  • TypedDict -- defines dicts with specific key names and types, giving type checkers something to check against in JSON-heavy code.

statistics Module Updates

New functions: statistics.mean() already existed, but 3.8 adds statistics.NormalDist, statistics.fmean() (float mean, faster), statistics.geometric_mean(), and statistics.multimode(). These land in the stdlib without needing scipy for basic distribution work.

Security and Audit Hooks (PEP 578)

Python 3.8 introduces runtime audit hooks -- a mechanism to observe or restrict sensitive operations like file opens, network connections, and subprocess launches. You register a hook via sys.addaudithook() and it receives events with associated arguments.

import sys

def my_audit(event, args):
    if event == "open":
        print(f"Opening file: {args[0]}")

sys.addaudithook(my_audit)

This is aimed at embedding scenarios and application-level monitoring, not kernel-level sandboxing. Hooks cannot be removed once added within a process.

Performance and CPython Internals

  • LOAD_GLOBAL is faster due to an optimized inline cache -- a measurable speedup in attribute-heavy code.
  • The vectorcall protocol (PEP 590) speeds up calls to C extension functions by reducing temporary object allocations. Functions like len(), isinstance(), and many others benefit.
  • Debug builds now share the ABI with release builds -- you no longer need separate debug-mode extension packages.
  • pickle defaults to Protocol 4 (was Protocol 3), improving performance and reducing output size for complex objects.
  • The PYTHONPYCACHEPREFIX env var redirects __pycache__ to a single location, useful for immutable source trees and containers.

FAQ

Is the walrus operator := the same as = in behavior?
No. The walrus operator returns the assigned value as an expression, so it can appear inside conditions, comprehensions, and function call arguments. Regular = is a statement and cannot appear inside expressions. The scoping rules also differ slightly -- walrus in a comprehension leaks to the enclosing scope, unlike loop variables in list comprehensions.

When does positional-only syntax actually matter for library authors?
When a parameter name is an implementation detail and you want freedom to rename it without breaking callers, or when you specifically want to prevent callers from using keyword syntax. The built-in pow(x, y, mod=None) is a good reference -- x and y are positional-only.

What does the TypedDict syntax look like in practice?
You can define it as a class or via the functional form. Class form is cleaner: class Movie(TypedDict): name: str; year: int. Type checkers then flag any dict literal that's missing required keys or has wrong types when assigned to a Movie annotation.

Do audit hooks from PEP 578 slow down normal code?
Only when events are actually triggered. There is a small overhead on operations that emit audit events (file opens, imports, etc.), but non-audited code paths are unaffected. The overhead is negligible for most applications.

Can I use shared_memory across machines, not just processes on the same host?
No. multiprocessing.shared_memory is strictly for processes on the same machine sharing physical memory. For cross-machine data sharing, you still need a network protocol or something like Redis or Apache Arrow Flight.

Releases In Branch 3.8

VersionRelease date
3.8.2006 Sep 2024
(1 year ago)
3.8.1919 Mar 2024
(2 years ago)
3.8.1824 Aug 2023
(2 years ago)
3.8.1706 Jun 2023
(3 years ago)
3.8.1606 Dec 2022
(3 years ago)
3.8.1511 Oct 2022
(3 years ago)
3.8.1406 Sep 2022
(3 years ago)
3.8.1316 Mar 2022
(4 years ago)
3.8.1230 Aug 2021
(4 years ago)
3.8.1128 Jun 2021
(5 years ago)
3.8.1003 May 2021
(5 years ago)
3.8.902 Apr 2021
(5 years ago)
3.8.819 Feb 2021
(5 years ago)
3.8.8rc116 Feb 2021
(5 years ago)
3.8.721 Dec 2020
(5 years ago)
3.8.7rc107 Dec 2020
(5 years ago)
3.8.623 Sep 2020
(5 years ago)
3.8.6rc107 Sep 2020
(5 years ago)
3.8.520 Jul 2020
(6 years ago)
3.8.413 Jul 2020
(6 years ago)
3.8.4rc129 Jun 2020
(6 years ago)
3.8.313 May 2020
(6 years ago)
3.8.3rc129 Apr 2020
(6 years ago)
3.8.224 Feb 2020
(6 years ago)
3.8.2rc217 Feb 2020
(6 years ago)
3.8.2rc110 Feb 2020
(6 years ago)
3.8.118 Dec 2019
(6 years ago)
3.8.1rc109 Dec 2019
(6 years ago)
3.8.014 Oct 2019
(6 years ago)
3.8.0rc101 Oct 2019
(6 years ago)
3.8.0b429 Aug 2019
(6 years ago)
3.8.0b329 Jul 2019
(7 years ago)
3.8.0b204 Jul 2019
(7 years ago)
3.8.0b104 Jun 2019
(7 years ago)
3.8.0a406 May 2019
(7 years ago)
3.8.0a325 Mar 2019
(7 years ago)
3.8.0a225 Feb 2019
(7 years ago)
3.8.0a103 Feb 2019
(7 years ago)