Stable Release in branch 2.4
2.4.6
Released 19 Dec 2008
(17 years ago)
SoftwarePython
Version2.4
Status
End of life
Initial release2.4
30 Nov 2004
(21 years ago)
Latest release2.4.6
19 Dec 2008
(17 years ago)
End of life19 Dec 2008
(Ended 17 years ago)
Source codehttps://github.com/python/cpython/tree/v2.4.6
Documentationhttps://docs.python.org/release/2.4.6/
Downloadhttps://www.python.org/downloads/release/python-246/
Python 2.4 ReleasesView full list

What Is New in Python 2.4

Python 2.4 was released on November 30, 2004. The standout additions are function and class decorators (@decorator syntax), built-in set and frozenset types, generator expressions, subprocess module as a unified process management API, and the Decimal type for exact decimal arithmetic. String formatting gained "{0}".format()-style syntax was not yet here, but the % operator gained new features.

Category Change PEP / Reference
New Syntax Function (and class) decorators: @decorator PEP 318
New Syntax Generator expressions: (x**2 for x in range(10)) PEP 289
Builtins set() and frozenset() become built-in types PEP 218
Builtins sorted() built-in function returning a new sorted list --
Builtins reversed() built-in for reverse iteration PEP 322
New Modules subprocess -- unified process management PEP 324
New Modules decimal -- exact decimal arithmetic PEP 327
Standard Library collections.deque -- O(1) append and popleft --
Standard Library cookielib, improvements to urllib2, better os.walk() --

Key Features in Python 2.4

Function Decorators (PEP 318)

The @decorator syntax arrived in 2.4 for functions. A decorator is syntactic sugar for func = decorator(func). This unlocked clean implementations of memoization, authentication, logging, and function transformation.

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"{func.__name__} took {time.time() - start:.3f}s")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(0.5)

Generator Expressions (PEP 289)

Generator expressions are like list comprehensions but lazy -- they produce values on demand without building the full list in memory. They use parentheses instead of square brackets.

# List comprehension -- builds entire list in memory
squares_list = [x**2 for x in range(10**6)]

# Generator expression -- one value at a time
squares_gen = (x**2 for x in range(10**6))
total = sum(squares_gen)  # no intermediate list created

Built-in set and frozenset

Sets became first-class built-ins in 2.4 (they were in a sets module before). set is mutable; frozenset is immutable and hashable (usable as a dict key or in another set).

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(a | b)   # union: {1, 2, 3, 4, 5, 6}
print(a & b)   # intersection: {3, 4}
print(a - b)   # difference: {1, 2}
print(a ^ b)   # symmetric difference: {1, 2, 5, 6}

Decimal -- Exact Decimal Arithmetic (PEP 327)

Binary floating-point arithmetic cannot exactly represent many decimal fractions. The decimal module provides arbitrary-precision decimal arithmetic, essential for financial calculations.

from decimal import Decimal, getcontext
getcontext().prec = 28

print(0.1 + 0.2)                   # 0.30000000000000004 (float)
print(Decimal("0.1") + Decimal("0.2"))  # 0.3 (exact)

FAQ

What is the difference between sorted() and list.sort()?
sorted() returns a new sorted list and accepts any iterable. list.sort() sorts in place and returns None. Both accept key and reverse arguments. Use sorted() when you want the original unmodified, or when the input is not a list.

Can I use a generator expression directly as a function argument?
Yes, if it is the only argument: sum(x**2 for x in range(10)) works without extra parentheses. With multiple arguments, you need the extra pair: max((x for x in items), key=len).

Why use Decimal instead of rounding floats?
Rounding floats is a workaround, not a fix. The representation error accumulates over repeated operations. Decimal stores numbers as true decimal fractions, so Decimal("0.10") * 3 gives exactly Decimal("0.30"), not 0.30000000000000004.

What replaced os.popen() and os.system() that subprocess was meant to fix?
os.popen(), os.popen2/3/4(), os.system(), commands.getoutput(), and others were scattered, inconsistent, and platform-specific. subprocess unified all of them with a single, cross-platform API and better security (no shell injection when using lists instead of strings).

When should frozenset be used over set?
When you need a set that is hashable -- as a dict key, as an element of another set, or as a function argument that should not be mutated by the callee. Frozensets are also thread-safe to read from multiple threads since they cannot be modified.

Releases In Branch 2.4

VersionRelease date
2.4.619 Dec 2008
(17 years ago)
2.4.6c113 Dec 2008
(17 years ago)
2.4.511 Mar 2008
(18 years ago)
2.4.5c102 Mar 2008
(18 years ago)
2.4.418 Oct 2006
(19 years ago)
2.4.4c110 Oct 2006
(19 years ago)
2.4.328 Mar 2006
(20 years ago)
2.4.3c123 Mar 2006
(20 years ago)
2.4.228 Sep 2005
(20 years ago)
2.4.2c120 Sep 2005
(20 years ago)
2.4.130 Mar 2005
(21 years ago)
2.4.1c217 Mar 2005
(21 years ago)
2.4.1c110 Mar 2005
(21 years ago)
2.430 Nov 2004
(21 years ago)
2.4c118 Nov 2004
(21 years ago)
2.4b203 Nov 2004
(21 years ago)
2.4b115 Oct 2004
(21 years ago)
2.4a302 Sep 2004
(21 years ago)
2.4a205 Aug 2004
(22 years ago)
2.4a108 Jul 2004
(22 years ago)