New Template Strings in Python 3.14
By Volodymyr Obrizan on May 15, 2025 · Read this post in other languages: Russian Ukrainian
In Python 3.14, a new language syntax extension appeared — template strings (t-strings). Let's consider what they are, why they were made, and how to work with them.
What are Template Strings?
Template strings (t-strings) are a generalization of f-strings, where instead of the prefix f
, t
is used. Instead of being evaluated as a str
type, t-strings are evaluated as an instance of a new immutable type — Template
(module string.templatelib
).
Important: do not confuse with Template Strings, which appeared in Python 2.4 back in 2004 (PEP 292) and look like this: s = Template('$who likes $what')
.
Let's look at an example showing the difference between f-strings and t-strings:
name = "Volodymyr Obrizan"
f_string = f"Hello, {name}"
template = t"Hello, {name}"
print("f-string: ", f_string)
print("t-string: ", template)
Terminal output:
f-string: Hello, Volodymyr Obrizan
t-string: Template(strings=('Hello, ', ''), interpolations=(Interpolation('Volodymyr Obrizan', 'name', None, ''),))
Note that the f-string f_string
was immediately evaluated into the string "Hello, Volodymyr Obrizan"
, whereas the t-string template
was not evaluated as a string but formed an object of type Template
. Thus, interpolation (template transformation) happens not instantly, but deferred.
How to process such templates?
How to process such templates to get a concrete string with already substituted values? The interpolation algorithm (transformation) must be defined by the user.
The Template
type object supports the __iter__
protocol, so you can sequentially get all parts of the template:
city = "Kharkiv"
weather = "20 C"
for item in t"Temperature in {city} is {weather}":
print(item, type(item))
Terminal output:
Temperature in <class 'str'>
Interpolation('Kharkiv', 'city', None, '') <class 'string.templatelib.Interpolation'>
is <class 'str'>
Interpolation('20 C', 'weather', None, '') <class 'string.templatelib.Interpolation'>
We see that Template
is built from 4 parts:
"Temperature in "
— string{city}
— object of typeInterpolation
" is "
— string{weather}
— object of typeInterpolation
Using iteration over Template
, you can write your own interpolation algorithm for such templates.
Interpolation example: secret_safe
Task: when outputting to log files or terminal, it is desirable to hide secrets: API keys, tokens, etc.
Let's develop an interpolation algorithm secret_safe
that should mask all values passed into the template. To determine whether a value in the template is a secret, we will use the function shannon_entropy(data: str) -> float
, which calculates entropy by the Shannon algorithm. If the entropy for a string exceeds a certain threshold (3.8 in the example) and the string length is more than 10 characters, we consider such a string a secret (function is_probably_secret
) and mask it: replacing the middle of the secret with asterisks: 123******890
.
The function secret_safe(template: Template) -> str
evaluates the template into a concrete string.
import math
from collections import Counter
from string.templatelib import Interpolation, Template
# Calculates Shannon entropy for a given string
def shannon_entropy(data: str) -> float:
return 0.0 if not data else -sum((count / len(data)) * math.log2(count / len(data)) for count in Counter(data).values())
# Checks if a string is probably secret (by length and entropy)
def is_probably_secret(s: str, threshold: float = 3.8) -> bool:
return len(s) > 10 and shannon_entropy(s) > threshold
# Processes the template and masks values that look like secrets
def secret_safe(template: Template) -> str:
parts: list[str] = []
for item in template:
# Iterate over all parts of the template
match item:
# If this is a regular text fragment
case str() as s:
parts.append(s)
# If this is a variable interpolation
case Interpolation(value, _, _, _):
# If the value looks like a secret — mask it
if is_probably_secret(value):
parts.append(str(item.value)[:3] + "*****" + str(item.value)[-3:])
else:
parts.append(str(item.value))
# Join all parts into one string
return "".join(parts)
Example 1. Login and password template:
login = "Volodymyr"
password = "aSalDsLOgrETAreFOLMA"
signup_template = t"Hi, {login}, your password is {password}."
print(secret_safe(signup_template))
Terminal output:
Hi, Volodymyr, your password is aSa*****LMA.
Example 2. Template for environment variables:
variables = {
"AWS_REGION": "us-west-1",
"AWS_OUTPUT_FORMAT": "json",
"AWS_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE",
"AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
for k, v in variables.items():
print(secret_safe(t"{k}={v}"))
Terminal output:
AWS_REGION=us-west-1
AWS_OUTPUT_FORMAT=json
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJa*****KEY
How do previous versions react to Template Strings?
If you try to use the t-string syntax in Python 3.13 and below, the interpreter will raise a SyntaxError: invalid syntax
:
File "/Users/obrizan/Projects/Experiments/template-strings/main.py", line 3
template = t"Hello, {name}"
^^^^^^^^^^^^^^^
SyntaxError: invalid syntax
Therefore, use this new syntax cautiously. If compatibility with previous Python versions (3.13 and below) is needed, you will have to wait before using template strings.
How to install Python 3.14?
Python 3.14.0b1 is the first public beta version of the Python 3.14 interpreter, released on May 7, 2025. The first beta is an important milestone in Python 3.14 development because developers will not add any new features, only bug fixes. The official release of Python 3.14.0 is scheduled for October 7, 2025.
Template strings are available in Python 3.14, but how to install it before the official release?
Using the package manager uv
Install the package manager uv
: installation instructions.
Check which Python interpreter versions are available for installation by running the command uv python list
in the terminal. This command shows which Python versions are already installed and available for download:
$ uv python list
cpython-3.14.0a6+freethreaded-macos-aarch64-none <download available>
cpython-3.14.0a6-macos-aarch64-none <download available>
cpython-3.13.3-macos-aarch64-none /opt/homebrew/bin/python3.13
cpython-3.13.3-macos-aarch64-none /opt/homebrew/bin/python3
cpython-3.13.2+freethreaded-macos-aarch64-none <download available>
cpython-3.13.2-macos-aarch64-none <download available>
cpython-3.13.1-macos-aarch64-none /usr/local/bin/python3.13
cpython-3.13.1-macos-aarch64-none /Library/Frameworks/Python.framework/Versions/3.13/bin/python3.13
cpython-3.13.1-macos-aarch64-none /Library/Frameworks/Python.framework/Versions/3.13/bin/python3
...
<other older versions>
At the time of writing this article, the alpha version Python 3.14.0a6 with identifier cpython-3.14.0a6-macos-aarch64-none
was available.
Download and install this version by running the command uv python install cpython-3.14.0a6-macos-aarch64-none
in the terminal:
$ uv python install cpython-3.14.0a6-macos-aarch64-none
Installed Python 3.14.0a6 in 2.59s
+ cpython-3.14.0a6-macos-aarch64-none
Using the installer
Go to the page Current Pre-release Testing Versions and find the link to the current beta version. At the time of writing this article, the beta version Python 3.14.0b1 was available. Go to the corresponding page and in the Files section select and download the installer for your operating system:
After installation, the Python 3.14 beta version will be available via the command python3.14
. You can check the version with the command in the terminal:
$ python3.14 --version
Python 3.14.0b1
Further reading
- Unravelling t-strings by Brett Cannon