C:\1990S\PYTHON.TXT

1991

Python: Readable Code Still Has Machinery Inside

Python's 1991 public debut combined clear control flow with useful objects, modules, and exceptions, making ordinary programming work easier to express.

8 min readCovers February 1991 public debut; original 0.9.1 distribution inspectedSoftware That Shaped the 1990s

A useful programming language has to survive the point at which a small script becomes somebody else’s responsibility. The script may still be short. Its assumptions have usually expanded.

A shell command can start the job. A C program can provide detailed control. Between them lies a large territory of file handling, administrative tools, experiments, and modest applications that need structure without requiring every supporting detail to be built by hand.

Python entered that territory publicly in 1991. Its appeal involved the shape of the code, but readability was supported by substantial machinery: built-in data types, functions, modules, exceptions, and classes. A short program could say something useful because its runtime already knew how to do a great deal of ordinary work.

That combination is the historical point worth keeping. Clear syntax helps a reader see what the author intended. The data model determines what the program actually does. Occasionally those two accounts need a meeting.

A practical language at a research institute

Guido van Rossum developed Python at CWI in Amsterdam. His origin account identifies experience with the ABC language and work on the Amoeba distributed operating system as major influences. ABC supplied useful ideas about high-level data and indentation, while Amoeba exposed a need for extensible scripting and better error handling.1

Van Rossum began the project during the 1989 Christmas holidays and describes posting it to Usenet in February 1991. That establishes the public debut without requiring an unsupported exact day.1

The original surviving 0.9.1 distribution calls itself the first beta release, patchlevel one. Its README invites comments about language design, portability, documentation, and modules. It reports development and testing on Unix systems and the Macintosh; possible MS-DOS portability is expressed as a hope rather than a completed platform guarantee.2

The source came with permission to use, copy, modify, and distribute it while retaining copyright and permission notices. This gave interested users a practical route to inspecting the implementation and returning fixes. It was an invitation to work on an existing system, not merely a description of an inaccessible language.2

Guido van Rossum at OSCON in 2006.

Guido van Rossum, July 26, 2006. Later portrait by Doc Searls, source, CC BY-SA 2.0. Downloaded Commons version includes previously applied rotation and color-balance changes; no new alterations.

Whitespace describes a boundary

Python’s indentation makes the grouping of statements visible. In the original grammar, a multiline statement suite uses INDENT and DEDENT tokens. A loop body therefore has a boundary that follows its indentation rather than a separate pair of braces.3

That is a language rule. It isn’t just an instruction to make code look tidy.

Here is an invented inventory calculation written using constructs present in the inspected 0.9.1 grammar and tutorial:

quantities = [3, 2, 5]
total = 0
for quantity in quantities:
    total = total + quantity
cost = total * 4
print total, cost

The mathematical result is a quantity total of ten and a cost of forty. The final line uses the period’s print statement rather than Python 3’s function-call syntax.

The indentation puts only the accumulation inside the loop. Multiplying by four occurs after all three quantities have been processed. At each iteration, total represents the sum of the values already visited: first three, then five, then ten.

That small invariant explains the calculation more clearly than merely watching the final answer appear. Before the loop starts, zero is the sum of no visited values. Each step adds the next value. At completion, all values have been visited, so the stored total is the whole sum.

Move the cost calculation inside the loop and it is repeated for each intermediate total. Keep the final print outside and the final numbers in this tiny example happen to remain the same, despite the extra work. Move printing inside too and the behavior visibly changes: the program reports successive intermediate answers. A misplaced line can alter the program even when its spelling is perfect.

This is a useful limit on the idea that readable code explains itself. Its structure makes reasoning easier. It doesn’t do the reasoning for you.

Names aren’t boxes containing private copies

Python’s objects deserve at least as much attention as its indentation. A name can refer to an object that another name also refers to. Assignment needn’t manufacture a new independent copy of the object.

The original tutorial documents mutable lists, list slicing, indexed replacement, and methods such as append. The implementation’s list code distinguishes creating a slice from replacing an item in an existing list.4

Consider another invented example:

original = [3, 2, 5]
alias = original
snapshot = original[:]
alias[1] = 9
print original
print snapshot

The resulting lists are:

[3, 9, 5]
[3, 2, 5]

alias and original refer to the same list. Replacing its item at index one changes what either name sees. snapshot refers to a separate outer list produced by slicing, so its middle value remains two.

Two names share a mutable list while a slice creates a separate outer list.

Original explanatory illustration, 2026. A model of references and a shallow list copy, not an interpreter memory dump or historical screenshot.

This distinction is easy to miss when a language makes assignment look comfortably simple. In everyday conversation, “give me a copy” can mean several things. A program needs a precise answer about whether the data itself has been duplicated or another reference to it has been supplied.

The slice is a shallow copy. It creates a new outer list while retaining references to its elements. With the integer elements above, that is enough to demonstrate independent item replacement. A nested mutable list exposes the next layer of the distinction.

For example, suppose nested contains [[1], [2]] and copy = nested[:]. Appending three to copy[0] changes the inner list shared by both outer lists. Both can then display [[1, 3], [2]]. The separate outer container didn’t recursively duplicate everything inside it.

This general explanation follows the original list-slicing implementation, which creates a list and retains references to selected elements. It isn’t a claim that the runtime secretly stores every object as a diagram with arrows. The arrows help a human keep track of relationships that the program must maintain.

The practical lesson is useful well beyond Python. When a function receives a mutable object, changes to that object may be visible to its caller. When a program needs independent state, its author must decide how much of the structure to copy. Friendly syntax can remove bookkeeping without making ownership disappear.

A method belongs to an object

The early tutorial explains result.append(value) as a call to a method of a list. The type supplies operations appropriate to that object; appending is one of the list’s operations.4

The user can therefore work with a useful collection without writing its storage management. Indexing, slicing, and appending express intentions at the level of the task. The implementation handles the changes needed to make those intentions concrete.

Classes extended the object model into user-defined structures, but the first beta didn’t have the complete modern class protocol. Its tutorial describes explicit object arguments in methods and an early construction arrangement. It says there are no special constructors or destructors; examples use an explicitly called new method rather than today’s customary __init__.5

A class could bring related behavior and data together. That doesn’t mean the 1991 language already had decorators, dataclasses, modern operator hooks, or all the other facilities a current programmer might expect. Historical resemblance is especially deceptive when much of a language still looks familiar.

One particularly visible difference appears in comparison syntax. The inspected early grammar uses a single equals sign for equality as well as assignment, with contextual restrictions explained in the tutorial. Writing a modern == comparison into an alleged 0.9.1 example would quietly change the historical language.3

Our examples avoid that issue rather than presenting modern syntax under an old date. They also avoid augmented assignment, comprehensions, and formatted string literals. An early program can be readable without receiving several decades of later improvements by accident.

Failures can have a route through the program

Python’s first beta also included exception-handling constructs. The original grammar and tutorial document try, except, and finally, alongside raising an exception.6

This matters when a program is doing more than arithmetic. An attempted operation can fail because a file is missing, an input is unsuitable, or a service cannot complete the request. A useful program needs to decide where that failure should be handled.

Exceptions provide a route out of the normal flow to a relevant handler. They don’t establish that every failure should be ignored, retried, or converted into a cheerful message. That choice belongs to the program’s author.

The original tutorial’s finally description identifies cleanup that runs when the protected work is left, including when an exception occurs. Separating normal work, error handling, and cleanup helps make their relationships visible. It can prevent the cleanup decision from being duplicated at every exit.

That is especially helpful in administrative and experimental code, where the successful path can be short and the awkward conditions numerous. The useful abstraction organizes those conditions; it doesn’t abolish them.

Readability was an engineering choice

Python’s public debut offered a combination that remains recognizable: expressive collections, visible control flow, reusable functions, modules, and an extensible implementation. Its original distribution invited feedback from users who could inspect and change the actual system.

The examples show why appearance and behavior both matter. Indentation makes the loop boundary legible. The list model explains why two names can observe the same mutation. A useful language has to support both the person reading the program and the machinery executing it.

There is also a restraint worth preserving in the history. The first beta was a promising working language, with specific platform tests and explicit limitations. It wasn’t already the contemporary ecosystem of scientific packages, web frameworks, and installation services. Those developments required later work by many contributors.

I like Python’s early design most when readability is treated as support for careful thought. A small program can reveal its structure without burying its purpose in scaffolding. The remaining obligation is to understand the objects and the consequences.

The code can be pleasant to read and still change the wrong list. At least it gives the reader a reasonably clear place to begin investigating.

Footnotes

  1. Official Python FAQ, Guido van Rossum’s retrospective origin account: CWI, ABC, Amoeba, 1989 work and February 1991 Usenet posting. Modern features elsewhere on the page are not treated as beta features. ↩ ↩2

  2. Official early releases and original 0.9.1 distribution, README, inspected directly. Patchlevel-one distribution is evidence about that beta, not a claim every later platform was tested in 1991. ↩ ↩2

  3. Original 0.9.1 archive, src/Grammar and doc/tut.tex, statements, indentation and comparisons. Link above supplies the preserved release; examples are original. ↩ ↩2

  4. Same original archive, doc/tut.tex list/method sections and src/listobject.c, especially list_slice and list_ass_item. Independent modern checks verify teaching examples but do not reproduce an original runtime. ↩ ↩2

  5. Same original archive, tutorial’s class prologue and Set example. Early construction and operator limitations distinguished from modern Python. ↩

  6. Same original archive, grammar and tutorial exception/finally sections. ↩

software-historypythonprogrammingcwilanguages