People ask about "F77 to Python" expecting a code transformation. The honest answer: the transformation worth making is not of the source but of everything around it. This post walks the dialect itself through a modern interface, and shows what changes and what deliberately does not, using canonical F77 constructs.
Fixed-form columns: parsed away, never imposed on Python
F77 lives in columns 1–72; continuation lives in column 6. The old parse has to juggle continuation-line joining and column-1 comments; the Python caller never sees any of this. The binding's generated code handles the dialect; the interface you call is irrelevant to column discipline.
Implicit typing: decided once, not per call
Variables typed by IMPLICIT rules (I-N is INTEGER, else
REAL) and DOUBLE PRECISION FUNCTION returns are
exactly where naive binding patterns skip routines — our
worked example's first discovery pass missed 24 of 49
routines including nine DOUBLE PRECISION
functions. In the modernized surface, each routine's signature
carries resolved types: the ambiguity is handled at generation
time, in one place, under tests — not in each caller's head.
COMMON blocks: invisible to Python, visible to the contract
Python never sees COMMON blocks directly, which is the point. What the API contract exposes instead is their consequence: the routines are stateful, so the interface constrains how calls may interleave. A generated Fortran service holds one native call at a time per process. In exported Python land, the same rule is documentation: one session, sequential, or drift will find you.
Arrays: Python does the typing, Fortran keeps the memory
What flows is a NumPy view of original memory where feasible.
The Python caller writes x = np.array([1.0, 2.0])
and the old REAL*8 X(10) convention behind it is
reconciled in the generated wrapper. What doesn't change: the
loan of memory, and the fact that the documented extents live
in the deck rather than the type system.
What does not change — deliberately
- The numerics: the same compiled units, the same answers, checked against a committed baseline.
- The stateful, seat-per-process concurrency character.
- The build dependency: a compiler is still in the production image.
"F77 to Python" done well is honest about this list: the language transition happens at the boundary only, and the promise that survives is numerical sameness with interface modernity.