What Is New in Python 2.3
Python 2.3 focused on polishing features from 2.2 and adding practical tools. Key additions include the sets module (before sets became built-in in 2.4), boolean values True and False as genuine built-in constants, the logging module, the itertools module with a suite of efficient iterator building blocks, and the datetime module for date and time arithmetic.
| Category | Change | PEP / Reference |
|---|---|---|
| Builtins | True and False as built-in Boolean constants |
PEP 285 |
| New Modules | logging -- hierarchical, configurable logging framework |
PEP 282 |
| New Modules | itertools -- chain, count, cycle, groupby, islice, product, etc. |
PEP 323 |
| New Modules | datetime -- date, time, timedelta, timezone-aware objects |
-- |
| New Modules | sets -- Set and ImmutableSet (predates built-in set) |
PEP 218 |
| New Modules | csv -- reading and writing CSV files |
PEP 305 |
| Standard Library | enumerate() built-in function |
PEP 279 |
| Standard Library | basestring common base for str and unicode |
-- |
| Performance | Timsort -- new stable sort algorithm, now used by all Python sort operations | -- |
Key Additions in Python 2.3
The logging Module (PEP 282)
Python 2.3 introduced the logging module, providing a hierarchical, level-based logging framework. Instead of scattering print statements, code logs to named loggers at levels DEBUG, INFO, WARNING, ERROR, and CRITICAL. Handlers route log records to the console, files, sockets, or email.
import logging
logging.basicConfig(level=logging.DEBUG, format="%(levelname)s: %(message)s")
logger = logging.getLogger("myapp")
logger.debug("Connecting to database")
logger.info("Request received")
logger.warning("Disk space low: %d%% free", 5)
logger.error("Failed to process request")
itertools -- Efficient Iterators
The itertools module provides building blocks for creating efficient iterators. All functions return iterators (lazy evaluation), making them memory-efficient even on very large data.
import itertools
# Chain multiple iterables
list(itertools.chain([1, 2], [3, 4], [5])) # [1, 2, 3, 4, 5]
# Group consecutive elements by a key
data = sorted([("a", 1), ("b", 2), ("a", 3)], key=lambda x: x[0])
for key, group in itertools.groupby(data, key=lambda x: x[0]):
print(key, list(group))
# Cartesian product
list(itertools.product("AB", repeat=2))
# [('A','A'), ('A','B'), ('B','A'), ('B','B')]
Timsort -- Python's Sort Algorithm
Python 2.3 replaced its previous sort with Timsort, a hybrid merge sort / insertion sort designed by Tim Peters. Timsort is stable (preserves equal elements' relative order), adaptive (fast on partially-sorted data), and performs at O(n log n) worst case. It was later adopted by Java (JDK 7+) and is now used in many other languages.
enumerate() Built-in (PEP 279)
enumerate(iterable) returns an iterator of (index, value) pairs, eliminating the pattern of i = 0; for item in seq: ... i += 1.
names = ["Alice", "Bob", "Carol"]
for i, name in enumerate(names, start=1):
print(f"{i}. {name}")
FAQ
Why was True/False not already a built-in before Python 2.3?
In Python 2.2 and earlier, True and False were just integer constants in the __builtin__ module (True = 1, False = 0) -- they could be overwritten. Python 2.3 introduced a genuine bool type that subclasses int, making True and False singletons that cannot be reassigned.
Is Timsort still used in modern Python?
Yes. Timsort is used by list.sort() and sorted() in all Python versions since 2.3 and remains the algorithm today. Its real-world performance is excellent -- most natural data has some existing order, and Timsort exploits "runs" to avoid unnecessary comparisons.
What is the difference between itertools.chain() and concatenating lists?
List concatenation with + or [*a, *b] builds a new list in memory. itertools.chain() creates a lazy iterator that yields from each iterable in turn without materializing all data. For large iterables or when you only need to iterate once, chain saves memory.
When should I use logging over print for debugging?
Always, in anything beyond a one-off script. Logging lets you control verbosity without changing code (just change the level), route output to different destinations, and disable all debug output in production by setting the root handler level to WARNING. A single logging.basicConfig() call configures the whole application.
Does datetime in Python 2.3 support timezones out of the box?
It provides the infrastructure (tzinfo abstract class) but not a timezone database. You had to implement your own tzinfo subclasses or use pytz. Python 3.9 added the zoneinfo module, which finally gives a stdlib timezone database.