Fundamentals 15 min read

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.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
New Python Standard Library Features: pathlib, secrets, zoneinfo, dataclasses, logging, f‑strings, tomllib, and setuptools

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.

PythonLoggingstandard-librarypathlibdataclassesf-strings
Python Programming Learning Circle
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.