New Python Standard Library Features: pathlib, secrets, zoneinfo, dataclasses, logging, f‑strings, tomllib, and setuptools
This article introduces the most useful additions and modern replacements in recent Python releases—including pathlib, the secrets module, zoneinfo, dataclasses, proper logging, f‑strings, the built‑in tomllib, and the transition from distutils to setuptools—showing why and how to adopt them in everyday code.
With each new Python version, new modules are added and better ways of doing things are introduced; while we are accustomed to older libraries, it is time to upgrade and take advantage of the newer, improved modules and features.
Pathlib
Pathlib is one of the largest recent additions to the Python standard library. It has been part of the library since Python 3.4, but many people still use the os module for filesystem operations.
Compared with the old os.path , pathlib offers many advantages: it uses an object‑oriented style instead of raw string paths, making code more readable and natural.
<code>from pathlib import Path
import os.path
# old way
two_dirs_up = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# new way, more readable
two_dirs_up = Path(__file__).resolve().parent.parent
</code>Because a path is treated as an object rather than a string, you can create the object once and then query its attributes or perform operations:
<code>readme = Path("README.md").resolve()
print(f"Absolute path: {readme.absolute()}")
print(f"File name: {readme.name}")
print(f"Path root: {readme.root}")
print(f"Parent directory: {readme.parent}")
print(f"File extension: {readme.suffix}")
print(f"Is it absolute: {readme.is_absolute()}")
</code>An especially handy feature is that the / operator can be used to join paths:
<code># Operators:
etc = Path('/etc')
joined = etc / "cron.d" / "anacron"
print(f"Exists? - {joined.exists()}")
</code>Pathlib replaces os.path but not the entire os module; it also includes glob functionality, so you can fully replace the combination of os.path and glob.glob with pathlib.
Secrets
Instead of the older os.urandom , you should use the secrets module introduced in Python 3.6 for generating cryptographically strong tokens.
<code># old way:
import os
length = 64
value = os.urandom(length)
print(f"Bytes: {value}")
print(f"Hex: {value.hex()}")
# new way:
import secrets
value = secrets.token_bytes(length)
print(f"Bytes: {value}")
value = secrets.token_hex(length)
print(f"Hex: {value}")
</code>The secrets module is preferred because it provides convenient utilities for hexadecimal and URL‑safe tokens, whereas the random module is not suitable for security‑critical purposes.
Zoneinfo
Before Python 3.9, timezone handling required third‑party libraries such as pytz . Starting with Python 3.9, the standard library includes zoneinfo , allowing you to replace pytz with a built‑in solution.
<code># old way (requires pytz)
from datetime import datetime
import pytz
dt = datetime(2022, 6, 4)
nyc = pytz.timezone("America/New_York")
localized = nyc.localize(dt)
print(f"Datetime: {localized}, Timezone: {localized.tzname()}, TZ Info: {localized.tzinfo}")
# new way (standard library)
from datetime import datetime
from zoneinfo import ZoneInfo
nyc = ZoneInfo("America/New_York")
localized = datetime(2022, 6, 4, tzinfo=nyc)
print(f"Datetime: {localized}, Timezone: {localized.tzname()}, TZ Info: {localized.tzinfo}")
</code>If your system lacks timezone data, install the tzdata package, which provides the IANA tz database.
Dataclasses
Python 3.7 introduced the dataclasses module as a modern replacement for namedtuple . Dataclasses are mutable, provide default implementations of repr , eq , init , and hash , allow default values, support inheritance, and from Python 3.10 also support frozen and slots .
<code># old way (namedtuple via typing)
from typing import NamedTuple
import sys
User = NamedTuple("User", [("name", str), ("surname", str), ("password", bytes)])
u = User("John", "Doe", b'tfeL+uD...')
print(f"Size: {sys.getsizeof(u)}")
# new way (dataclass)
from dataclasses import dataclass
@dataclass()
class User:
name: str
surname: str
password: bytes
u = User("John", "Doe", b'tfeL+uD...')
print(u)
print(f"Size: {sys.getsizeof(u)}, {sys.getsizeof(u) + sys.getsizeof(vars(u))}")
</code>Dataclasses are generally larger than namedtuples because they store attributes in a dict , but attribute access speed is comparable unless you create millions of instances.
Proper Logging
For production‑ready programs you should use the logging module instead of print . A simple configuration provides timestamps, file name, line number, and log level.
<code>import logging
logging.basicConfig(
filename='application.log',
level=logging.WARNING,
format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
datefmt='%H:%M:%S'
)
logging.error("Some serious error occurred.")
logging.warning('Some warning.')
</code>f‑strings
f‑strings offer a natural, readable, and fast way to format strings. However, in logging you may still need the old % style because it defers interpolation until the message is actually emitted, which can improve performance when many messages share the same template.
<code># using % formatting with logging (deferred)
logger.error("Message: %s", things)
# using f‑string (immediate evaluation)
logger.error(f"Message: {things}")
</code>For dynamic formatting where the template itself changes at runtime, you must use the older .format or % methods.
Tomllib
Starting with Python 3.11, the built‑in tomllib module can parse TOML files, eliminating the need for external dependencies such as tomli .
<code># reading a pyproject.toml file
import tomllib
with open("pyproject.toml", "rb") as f:
config = tomllib.load(f)
print(config)
# parsing a TOML string
toml_string = """
[project]
name = "another-app"
description = "Example Package"
version = "0.1.1"
"""
config = tomllib.loads(toml_string)
print(config)
</code>Setuptools
Distutils is deprecated; you should replace it with setuptools . The setuptools documentation and PEP 632 provide migration guidance.
Conclusion
Each new Python release brings new modules and deprecations. Regularly reviewing the "New Modules", "Deprecated Modules", and "Removed Modules" sections of the release notes helps you keep your projects up‑to‑date with the latest features and best practices.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.