Comparison · Perl 5 vs Python 3

Perl or Python for a log-shaping pipeline?

One task, two implementations, the same input file, and a decision matrix that names its own limits. Nobody wins this outright, and the page is structured so you can see why.

Reviewed
Reading time
14 minutes
Benchmark
Not run
Examples
Not CI-tested

01

The task

Read a mixed-format access log from standard input, extract five fields, normalise timestamps to UTC, drop bot traffic by user-agent pattern, and emit newline-delimited JSON — as a single file that a colleague can run without a build step.

Constraints

  • Runs on a stock Linux host with no package installation permitted.
  • Input is 2–20 GB per run, streamed, never fully in memory.
  • The person maintaining it in two years may not be the person writing it.

Scope If your job differs on any of those three constraints, the conclusion below does not transfer. The third constraint in particular is the one that flips the answer most often.

02

Decision summary

For this task the two are close enough that the deciding factor is your environment, not the language. Perl wins when you cannot install anything and the transformation is regex-shaped. Python wins when the output schema is going to grow, or when the maintainer pool is larger. Anyone who tells you one is categorically faster here has not defined the task.

03

Choosing between them

Choose Perl when

  • You cannot install packages and need more than shell provides — Perl 5 is present on effectively every Unix host.
  • The core of the work is pattern extraction and rewriting, where the regex engine is the program.
  • The script must stay a single file with no virtualenv and no lockfile.
  • You are already maintaining Perl in this codebase and consistency is worth more than novelty.

Choose Python when

  • The output schema will grow into structured records with validation.
  • You need the wider library surface for downstream analysis in the same process.
  • The maintainer pool matters more than startup footprint.
  • You want type annotations as a maintenance aid on a long-lived pipeline.

04

Environment and versions

No environment recorded This comparison publishes its decision framework only. Nothing was executed on measured hardware, so there is no OS, CPU, Perl version or Python version to report. The fields exist in the content model and stay empty until a run happens.
Operating system
Not recorded
CPU
Not recorded
Perl
Not recorded
Python
Not recorded

05

The two implementations

Both satisfy the task statement exactly. Both are written for a competent maintainer rather than for a benchmark. A line-by-line diff between two languages would be noise — the lines were never going to match — so the files are segmented by what each passage is doing instead. Pick a stage and both sides mark the passages that answer it.

Stages

What differs here

Nothing is selected, so both files are shown in full. Pick a stage on the left to mark the passages that implement it on both sides — and to read what actually changes there.

shape-log.pl · core modules only Perl 5no CPAN
#!/usr/bin/perl
use strict;
use warnings;
use JSON::PP ();
use Time::Piece;
my $json = JSON::PP->new->canonical;my $bot  = qr/bot|crawler|spider|slurp/i;my $line_re = qr/^(\S+) \S+ \S+ \[([^\]]+)\] "([^"]*)" (\d{3}) (\S+)/;
sub to_utc {
    my $t = Time::Piece->strptime($_[0], '%d/%b/%Y:%H:%M:%S %z');
    return gmtime($t->epoch)->datetime . 'Z';
}
while (my $line = <STDIN>) {    next if $line =~ $bot;    my ($ip, $ts, $req, $status, $bytes) = $line =~ $line_re or next;
    print $json->encode({
        ip     => $ip,
        ts     => to_utc($ts),
        req    => $req,
        status => 0 + $status,
        bytes  => $bytes eq '-' ? 0 : 0 + $bytes,
    }), "\n";}
shape_log.py · standard library only Python 3no pip
#!/usr/bin/env python3
import json, re, sys
from datetime import datetime, timezone
LINE = re.compile(r'^(\S+) \S+ \S+ \[([^\]]+)\] "([^"]*)" (\d{3}) (\S+)')BOT  = re.compile(r'bot|crawler|spider|slurp', re.I)

def to_utc(ts: str) -> str:
    dt = datetime.strptime(ts, "%d/%b/%Y:%H:%M:%S %z")
    return dt.astimezone(timezone.utc).isoformat().replace("+00:00", "Z")

for line in sys.stdin:    if BOT.search(line):
        continue    m = LINE.match(line)
    if not m:
        continue
    ip, ts, req, status, size = m.groups()    print(json.dumps({
        "ip": ip,
        "ts": to_utc(ts),
        "req": req,
        "status": int(status),
        "bytes": 0 if size == "-" else int(size),
    }, sort_keys=True))

Both files are 27 lines. That symmetry is not a trick of formatting — it is what happens when two competent implementations answer the same five questions, and it is the reason a raw line-count comparison would have told you nothing.

06

Results

Benchmark · status

Not run

No benchmark has been executed for this comparison. When one is, it will publish the harness, the input corpus checksum, the hardware, the number of runs and the variance — or it will not publish.

This block is deliberately empty rather than filled with a chart of numbers we did not measure. An outline chart with no data behind it would be worse than nothing.

07

Tradeoff matrix

Five dimensions. Each carries which way it leans, how confident we are, and the basis for that confidence. A dimension with no basis is published as none rather than being quietly dropped.

Decision dimensions · 5

No scores, no stars
Five decision dimensions comparing Perl and Python for the stated task, each with a lean, a confidence level and the basis.
DimensionPerlPython LeansConfidenceBasis
Availability without installation Present on essentially every Unix-like host, including minimal container base images that ship a full perl. Usually present on Linux distributions, but the version varies and minimal images increasingly ship without it. Perl High Widely observable property of common base images; not a benchmark.
Regex ergonomics Regex is language syntax. Match, substitute and bind read as one operation. Regex is a library. Correct, capable, and consistently more verbose for substitution-heavy work. Perl High Language design, directly inspectable in the code above.
Structured output and validation JSON::PP is in core and adequate. Schema validation means reaching for CPAN. json is in the standard library; dataclasses and validation libraries are a well-trodden path. Python Medium Standard-library surface, verifiable from each language’s documentation.
Throughput on the stated task Not measured Not measured Unknown None No benchmark has been run. We are not going to repeat someone else’s numbers on hardware we did not measure.
Maintainability by the next person Depends heavily on discipline: strict, warnings, named subs and no clever punctuation variables. More conventional defaults, and a larger pool of people who will recognise the idioms. Python Low Judgement, not measurement. Weight it against your own team.

The lean column carries a glyph as well as a colour, and the confidence column is plain text — nothing in this table depends on you being able to distinguish two hues.

08

Weigh it against your situation

The table above is our evidence. What it is worth depends entirely on which constraints you are actually under, and we cannot see those from here. So set them yourself: mark each dimension irrelevant, relevant or decisive, and the page reports where your weighting lands against our dimensions.

What this is not It is not a score, and the result is not a recommendation. Nothing here is normalised into a rating, no dimension is secretly worth more than another, and a dimension we have no basis for stays out of the tally no matter how heavily you weight it.
Availability without installation Confidence high · observable property of common base images
How much does availability without installation matter on your job?

Leans Perl

Regex ergonomics Confidence high · language design, inspectable above
How much do regex ergonomics matter on your job?

Leans Perl

Structured output and validation Confidence medium · standard-library surface
How much does structured output and validation matter on your job?

Leans Python

Throughput on the stated task Confidence none · no benchmark was run — this cannot be counted
How much does throughput matter on your job? Note that we have no data for this dimension.

No basis

Maintainability by the next person Confidence low · judgement, not measurement
How much does maintainability by the next person matter on your job?

Leans Python

09

Methodology

  1. The task statement is the contract. Both implementations must satisfy it exactly; anything either one does extra is out of scope.
  2. Code samples are written for readability by a competent maintainer, not for benchmark scores.
  3. Dimensions carry an explicit confidence level. none means we have no basis and say so instead of guessing.

10

Limitations

Read this before you cite the page
  • No throughput measurement. Any performance claim you take from this page is one we did not make.
  • Single task shape. Results do not generalise to CPU-bound numeric work, where neither language is the right answer.
  • Version-sensitive. Both languages move; re-read the reviewed date before relying on this.

11

Corrections and discussion

If a dimension is wrong, say which one and why. Corrections that name a dimension and cite a source are applied and credited; the reviewed date moves when they are.

Public correction trail Prefer a public record? Open a sourced issue in the PerlCoders repository.