Modern Python Standard Library: Pathlib, Secrets, ZoneInfo, Dataclasses, Logging, f‑strings, Tomllib, and Setuptools
This article reviews several modern Python standard‑library modules—Pathlib, Secrets, ZoneInfo, Dataclasses, proper logging, f‑strings, Tomllib, and Setuptools—explaining why they replace older alternatives and providing concise code examples to help developers adopt best practices and keep their projects up‑to‑date.
Python continuously adds new standard‑library modules; this article highlights several modern replacements for older approaches and demonstrates their usage with concise code examples.
Pathlib instead of os
Pathlib, introduced in Python 3.4, offers an object‑oriented API for filesystem paths, improving readability and allowing operations like Path(__file__).resolve().parent.parent and using the division operator to join paths.
<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
two_dirs_up = Path(__file__).resolve().parent.parent
</code>Path objects expose useful properties such as .absolute() , .name , .root , .parent , .suffix , and .is_absolute() .
<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>Pathlib also supports the / operator for path concatenation.
<code>etc = Path('/etc')
joined = etc / "cron.d" / "anacron"
print(f"Exists? - {joined.exists()}")
</code>Secrets instead of os.urandom
The secrets module (available since Python 3.6) should replace os.urandom for generating cryptographically strong tokens.
<code># old way
import os
value = os.urandom(64)
print(f"Bytes: {value}")
print(f"Hex: {value.hex()}")
# new way
import secrets
value = secrets.token_bytes(64)
print(f"Bytes: {value}")
value = secrets.token_hex(64)
print(f"Hex: {value}")
</code>ZoneInfo instead of pytz
Python 3.9 introduced zoneinfo as the standard way to handle time zones, replacing the external pytz library.
<code># old way
import pytz
from datetime import datetime
nyc = pytz.timezone("America/New_York")
localized = nyc.localize(datetime(2022, 6, 4))
print(f"Datetime: {localized}, Timezone: {localized.tzname()}, TZ Info: {localized.tzinfo}")
# new way
from zoneinfo import ZoneInfo
from datetime import datetime
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 the system lacks zone data, install the tzdata package.
Dataclasses instead of NamedTuple
Python 3.7 added dataclasses as a flexible alternative to NamedTuple , offering mutability, default values, and automatic method generation.
<code># old way (namedtuple)
from typing import NamedTuple
class User(NamedTuple):
name: str
surname: str
password: bytes
# new way (dataclass)
from dataclasses import dataclass
@dataclass()
class User:
name: str
surname: str
password: bytes
</code>Dataclasses are larger in memory because they store attributes in a dict, but attribute access speed is comparable.
Proper Logging instead of print
For production code, use the logging module rather than print statements.
<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 instead of format
f‑strings provide readable, high‑performance string interpolation, though % formatting may still be useful for deferred logging.
<code># logging with % formatting (deferred)
logger.error("Message: %s", things)
# immediate evaluation with f‑string
logger.error(f"Message: {things}")
</code>Tomllib instead of tomli
Python 3.11 includes the built‑in tomllib module for parsing TOML, removing the need for the external tomli package.
<code>import tomllib
with open("pyproject.toml", "rb") as f:
config = tomllib.load(f)
print(config)
toml_string = """
[project]
name = "another-app"
description = "Example Package"
version = "0.1.1"
"""
config = tomllib.loads(toml_string)
print(config)
</code>Setuptools instead of distutils
Since distutils is deprecated, migrate to setuptools for packaging; see PEP 632 for migration guidance.
Conclusion
Each new Python release adds useful modules and deprecates old ones. Regularly reviewing the release notes for “new modules”, “deprecated modules”, and “removed modules” helps you keep your projects modern and maintainable.
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.