Free Python reference · JavaScript timeline

Python 3.14: Separate interpolation from rendering

Template strings retain values for processing; annotations defer evaluation; native concurrency options continue evolving.

Released · Editorial review October 25, 2026

Introduced in Python 3.14 · Syntax

Template strings with a t prefix

A t-string resembles an f-string but produces a Template object rather than a finished string. It retains static text and interpolation values so a processor can choose how to handle them.

This separation is useful for custom formatting or context-aware processing. It is not automatic escaping: the code that consumes the template must implement the appropriate rules for its destination. In particular, creating a template does not by itself make HTML or SQL safe.

The example inspects the two pieces of static text and the interpolated value. The expression is evaluated when the template is created; later rendering choices belong to the consumer.

Worked example

Minimum Python 3.14 · Run locally

name = "Ada"
message = t"Hello, {name}!"
print(type(message).__name__)
print(message.strings)
print(message.interpolations[0].value)

Expected output

Template
('Hello, ', '!')
Ada

Example checked with CPython 3.14.8, CPython 3.15.0.

Common mistake

A Template is not a str. Do not send it to an API expecting a string without a deliberate rendering or processing step.

Try it yourself

Change name to text containing angle brackets. Explain why merely storing it in a template has not escaped it for HTML.

Read more: Python 3.14 release notes · PEP 750

Introduced in Python 3.14 · Language behavior

Annotations are evaluated when needed

By default, Python 3.14 defers evaluation of annotations instead of evaluating them immediately when a definition runs. Forward references can therefore name a class that will be defined later, provided it exists when an operation actually needs the value.

annotationlib offers tools for inspecting annotations in different formats. Asking for values can execute annotation expressions and still raise an error if a name is unresolved. Annotation inspection should therefore be treated as evaluation of code, not as reading inert labels.

This behavior differs from the earlier optional from __future__ import annotations, which stores string forms. The example intentionally has no future import and requests values after the class exists.

Worked example

Minimum Python 3.14 · Run locally

from annotationlib import get_annotations

def identity(value: Later) -> Later:
    return value

class Later:
    pass

annotations = get_annotations(identity)
print(annotations["value"] is Later)
print(annotations["return"] is Later)

Expected output

True
True

Example checked with CPython 3.14.8, CPython 3.15.0.

Common mistake

Deferred does not mean never evaluated. Accessing value-form annotations before Later exists can still fail, and annotations still do not validate calls.

Try it yourself

Move get_annotations(identity) above the class definition. Predict the exception and explain the point at which the name is needed.

Read more: Python 3.14 release notes · PEP 649

Introduced in Python 3.14 · Standard library

Multiple interpreters through the standard library

concurrent.interpreters exposes separate Python interpreters within one native process. Each has its own interpreter state. This is different from creating ordinary threads that directly share the same Python objects.

Isolation changes the communication model: work and data must be sent using supported mechanisms. This is useful background for understanding InterpreterPoolExecutor, but it is not a replacement for designing data ownership and failure handling.

The example creates one interpreter, executes a small assertion in it, and closes it in a finally block. Run it in native CPython; browser WebAssembly environments do not provide the same capability.

Worked example

Minimum Python 3.14 · Run locally

from concurrent import interpreters

worker = interpreters.create()
try:
    worker.exec("assert 6 * 7 == 42")
finally:
    worker.close()
print("worker closed")

Expected output

worker closed

Example checked with CPython 3.14.8, CPython 3.15.0.

Common mistake

Separate interpreters do not automatically share your local variables or support every extension module. Close resources even when work raises an exception.

Try it yourself

Change the assertion so it fails. Confirm cleanup still happens, and describe what the caller needs to report.

Read more: Python 3.14 release notes · PEP 734

Introduced in Python 3.14 · Interpreter capability

Free-threading becomes supported

Python 3.14 advances free-threaded CPython from the experimental status introduced in 3.13 to a supported option. It remains a distinct build choice rather than a promise that every ordinary installation runs without a GIL.

Extension modules may need compatible builds, and shared mutable data still needs a synchronization design. A program being correct under a GIL-enabled interpreter is not sufficient evidence that it is safe with true parallel access.

The diagnostic below reports the current GIL state on CPython. Its output depends on the running build and loaded extensions. It illustrates an inspection step, not a performance benchmark or a browser capability.

Worked example

Minimum Python 3.14 · Run locally

import sys
print(sys._is_gil_enabled())

Expected output

True

True is the result on the tested standard GIL-enabled CPython build. A free-threaded build may report False; that configuration is not benchmarked here.

Example checked with CPython 3.14.8, CPython 3.15.0.

Common mistake

Do not advertise free-threading as a feature of every Python 3.14 binary. Confirm the actual build and dependency support first.

Try it yourself

If the diagnostic prints False, identify one mutable object in your application that multiple threads could access and explain how ownership should work.

Read more: Python 3.14 release notes · PEP 779

Recap

Template strings retain values for processing; annotations defer evaluation; native concurrency options continue evolving. Prefer the clearest form that works on your project's supported Python versions.

Read the full Python 3.14 release notes →