Stable Release
1.4
Released 25 Oct 1996
(29 years ago)
SoftwarePython
Version1.4
Status
End of life
Initial release1.4
25 Oct 1996
(29 years ago)
Latest release1.4
25 Oct 1996
(29 years ago)
End of lifeTBD
Source codehttps://github.com/python/cpython/tree/v1.4
Documentationhttps://docs.python.org/release/1.4/
Downloadhttp://legacy.python.org/download/releases/binaries-1.4/
Python 1.4 ReleasesView full list

What Is New in Python 1.4

Python 1.4 introduced keyword arguments in function calls, access control via __getattr__/__setattr__, built-in complex number support, and the __repr__ / __str__ distinction. Python 1.4 also refined the exception hierarchy and improved the standard library significantly. It was the first Python version to get serious traction beyond academic and research circles.

Category Change Notes
Language Keyword arguments in function calls Enabled func(name="Alice", age=30)
Language Access to keyword arguments in functions via **kwargs The **kw calling convention
Language Built-in complex number type 3+2j literals; complex(real, imag)
Language __repr__ distinct from __str__ Formal separation of developer repr vs. user-facing str
Standard Library Early Tkinter improvements for GUI programming --
Standard Library Improved exception hierarchy Precursor to the normalized hierarchy in later versions
Platform Windows NT support improved --

Key Features in Python 1.4

Keyword Arguments and **kwargs

Python 1.4 added the ability to call functions using keyword arguments (func(name="Alice")) and to accept an arbitrary keyword argument dictionary with **kwargs. These features enabled more flexible and readable APIs and are still cornerstones of Python's function calling convention.

def configure(host, port=8080, **options):
    print(f"host={host}, port={port}, extras={options}")

configure("localhost", port=9090, debug=True, timeout=30)
# host=localhost, port=9090, extras={'debug': True, 'timeout': 30}

Complex Number Type

Python 1.4 added a built-in complex type with literal syntax 3+2j (note: j not i, to avoid confusion with the identifier i). Complex numbers support all arithmetic operations and have .real and .imag attributes.

z1 = 3 + 2j
z2 = 1 - 1j
print(z1 + z2)   # (4+1j)
print(z1 * z2)   # (5-1j)
print(z1.real)   # 3.0
print(z1.imag)   # 2.0
print(abs(z1))   # 3.605... (modulus)

__repr__ vs __str__

Python 1.4 formalized the distinction: __repr__ should return an unambiguous, ideally eval-able representation for developers; __str__ should return a human-readable representation. When only __repr__ is defined, Python falls back to it for str(). The convention is: if repr output is valid Python, then eval(repr(obj)) == obj.

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __repr__(self):
        return f"Point({self.x!r}, {self.y!r})"

    def __str__(self):
        return f"({self.x}, {self.y})"

p = Point(1, 2)
print(repr(p))  # Point(1, 2)  -- developer view
print(str(p))   # (1, 2)       -- user view

FAQ

When should **kwargs be used vs explicit keyword parameters?
Use explicit keyword parameters when you know the parameter names and want type-checker support and clear documentation. Use **kwargs for pass-through wrappers, decorators that need to forward arguments, and configuration-style functions where the set of options is open-ended. Avoid **kwargs in APIs where discoverability matters -- it effectively hides the accepted parameters.

Why does Python use j instead of i for imaginary numbers?
In engineering and signal processing, j is the standard notation for the imaginary unit (because i is already used for current in electrical engineering). Python chose j to align with engineering convention. In mathematics, i is common, but Python prioritizes the engineering use case where complex numbers are most practically applied.

Should __repr__ always return eval-able output?
It is a good goal but not always practical. The Python docs say it should be "unambiguous" and "if at all possible, should look like a valid Python expression." For objects with complex state or external resources, a non-eval-able but informative <ClassName ...> form is acceptable. The key is that repr should give a developer enough information to understand the object's state.

Were keyword arguments available before Python 1.4?
No. Before 1.4, all function arguments had to be positional. Python 1.4 added both the calling convention (func(name="value")) and the parameter capture (**kwargs) simultaneously. This was a significant API design unlock -- many Python idioms like dict(key=value) and open(file, encoding="utf-8") depend on it.

Is the complex type useful outside scientific computing?
Occasionally. Besides scientific and engineering use cases, complex numbers appear in signal processing (FFT), rotation mathematics, and some algorithm problems that model 2D geometry in the complex plane. For ordinary application development, floating-point or integer arithmetic is sufficient.

Releases In Branch 1.4

VersionRelease date
1.425 Oct 1996
(29 years ago)
1.4b326 Aug 1996
(29 years ago)
1.4b208 Aug 1996
(29 years ago)
1.4b101 Jul 1996
(29 years ago)