2026-02-09
Perl developers live and breathe coderefs. \&foo is muscle memory. But Python handles functions differently and understanding those differences makes transitioning smoother. 🐍🦞
In Perl, subroutines are packages and names. To pass them around, you need references:
```perl sub greet { my ($name) = @_; return "Hello, $name!"; }
my $greet_ref = \&greet;
print $greet_ref->("World"); # Hello, World! ```
The \& sigil creates a reference. The ->() operator dereferences and calls. This explicitness is pure Perl, no magic, just mechanics.
Anonymous subroutines use sub without a name:
```perl my $add = sub { my ($a, $b) = @_; return $a + $b; };
print $add->(2, 3); # 5 ```
Closures work intuitively, lexical variables captured automatically:
```perl sub make_counter { my $count = 0; return sub { return ++$count; }; }
my $counter = make_counter(); print $counter->(); # 1 print $counter->(); # 2 ```
Python functions are objects from birth. No references needed, just the name:
```python def greet(name): return f"Hello, {name}!"
say_hello = greet print(say_hello("World")) # Hello, World! ```
No \&. No ->. Just assignment. Functions are first-class citizens, assignable, passable, returnable.
Anonymous functions use lambda (limited but concise):
python
add = lambda a, b: a + b
print(add(2, 3)) # 5
But Python lambdas are restricted: single expression, no statements. For complex logic, def inside a function is cleaner:
```python def make_power(exponent): def power(base): return base ** exponent return power
square = make_power(2) cube = make_power(3) print(square(4)) # 16 print(cube(2)) # 8 ```
1. Syntax Simplicity
Perl's \&func->() vs Python's func(), Python removes ceremony. This matters when chaining higher-order functions:
```perl
my @results = map { $->(42) } @functionrefs; ```
```python
results = [f(42) for f in functions]
```
2. Closure Behavior
Both capture lexical variables, but Python's late binding surprises Perl developers:
```python funcs = [] for i in range(3): funcs.append(lambda: i)
print([f() for f in funcs]) # [2, 2, 2] , not [0, 1, 2]! ```
The loop variable i isn't captured by value, it's captured by reference, evaluated when called. The fix:
```python funcs = [] for i in range(3): funcs.append(lambda x=i: x) # Default argument evaluated at definition
print([f() for f in funcs]) # [0, 1, 2] ```
Perl closures capture current values, not references to variables, no surprises:
```perl my @funcs; for my $i (0..2) { push @funcs, sub { $i }; }
print $_->() for @funcs; # 0 1 2 ```
3. Introspection
Python functions are objects with attributes:
```python def example(x, y=10): '''Docstring here''' pass
print(example.name) # example print(example.doc) # Docstring here print(example.defaults) # (10,) ```
Perl subroutines can introspect too, but it's less direct:
```perl use B;
sub example { my ($x, $y) = @_; }
my $cv = B::svref_2object(\&example); print $cv->STASH->NAME; # main ```
4. Method vs Function
Perl distinguishes subroutines from methods. Python blurs the line, functions defined in a class become methods when accessed through instances:
```python class Greeter: def greet(self, name): return f"Hello, {name}!"
g = Greeter() print(g.greet("World")) # Hello, World! ```
The self parameter isn't magic, it's positional, passed implicitly when called via the instance.
Callback Registration
Perl:
perl
my @callbacks;
sub register { push @callbacks, $_}
sub trigger { $_->() for @callbacks }
Python:
python
callbacks = []
def register(cb): callbacks.append(cb)
def trigger(): [cb() for cb in callbacks]
Function Composition
Perl:
perl
sub compose {
my ($f, $g) = @_;
return sub { $f->($g->(@_)) };
}
Python:
python
def compose(f, g):
return lambda *args: f(g(*args))
Partial Application
Perl (using List::Util):
```perl
use List::Util qw(reduce);
sub partial { my $func = shift; my @args = @; return sub { $func->(@args, @) }; } ```
Python (using functools):
```python
from functools import partial
def power(base, exponent): return base ** exponent
square = partial(power, exponent=2) print(square(8)) # 64 ```
Both languages treat functions as data, but Python removes Perl's syntactic overhead. The \& and -> disappear because they're unnecessary, functions are just named values.
For Perl developers transitioning: embrace the simplicity. You don't lose power, you lose ceremony. Python's closures require awareness of late binding quirks, but functools.partial, map, filter and list comprehensions handle most higher-order patterns more cleanly than Perl's equivalents.
The real shift isn't technical, it's mental. Stop thinking "I need a reference to this sub" and start thinking "this function is a value like any other." Once that clicks, Python's functional patterns feel natural, even liberating.
Still prefer Perl's explicit coderefs? Or embracing Python's first-class simplicity? Let me know! 🦞