Plate 61
methodcaller vs getattr Call: Localhost Lab
Hands-on operator.methodcaller vs getattr vs direct: real calls/s invoking methods on many objects, measured on Linux localhost today in this lab for SREs.
Aditya Challa4 min read
Intro — what this post promises
Call a method on many objects: operator.methodcaller, getattr(obj, name)(), direct obj.method(), and pre-bound methods. This lab reports calls/s on Linux localhost.
It is not attrgetter (lab 65) or itemgetter (lab 59) — those fetch attributes/items; this invokes methods.
Related links:
- attrgetter vs getattr localhost lab
- itemgetter vs lambda sort localhost lab
- functools partial vs lambda localhost lab
- groupby vs manual localhost lab
- hmac compare digest localhost lab
- argparse vs sys argv localhost lab
- futures as completed vs wait localhost lab
- fnmatch vs re localhost lab
Lab honesty (1 Oct 2026 IST): Python 3.13.5. Affiliates: 0. No Docker. Widget.value() / Widget.add(1).
Verdict up front (10 000 objects): direct value() ~30.38 Mcalls/s; getattr ~17.04; methodcaller ~13.53; prebound calls ~29.68. Use methodcaller for clean map/sorted key hooks; direct calls when the name is fixed in code.
Arms
| Arm | Pattern |
|---|---|
| direct | w.value() |
methodcaller("value") | reusable caller |
getattr(w, "value")() | dynamic name |
| bind-each-time | [w.value for w in …] then call |
| prebound | bind once, call many |
add(1) variants | methodcaller with args |
Lab topology
Script: lab-evidence/99-methodcaller-vs-getattr/results/run_lab.py.
Lead table — n=10 000 (p50 Mcalls/s)
| Arm | Mcalls/s |
|---|---|
direct value() | 30.38 |
| prebound then call | 29.68 |
| getattr + call | 17.04 |
methodcaller value | 13.53 |
| bind-each + call | 12.48 |
Direct and prebound sit near the top. methodcaller pays for a portable callable. Binding a fresh method object every outer loop (bound_methods) is the costly anti-pattern.
With argument (add(1), n=10 000)
| Arm | Mcalls/s |
|---|---|
| direct | 22.44 |
| methodcaller("add", 1) | 16.87 |
| getattr + call | 14.24 |
With a bound argument, methodcaller closes some of the gap vs getattr — still behind a direct call on this box.
Scale check (value())
| n | direct | methodcaller | getattr | prebound |
|---|---|---|---|---|
| 1 000 | 19.35 | 10.61 | 17.27 | 29.39 |
| 10 000 | 30.38 | 13.53 | 17.04 | 29.68 |
| 50 000 | 29.56 | 19.56 | 15.62 | 28.89 |
Absolute rates move with cache effects; the ordering (direct / prebound ahead of dynamic lookup) is the useful takeaway.
map/sorted fit
methodcaller shines when an API wants a one-argument callable: sorted(objs, key=methodcaller("score")) or map(methodcaller("strip"), lines). That clarity often matters more than a few Mcalls/s on a microbench. Pair with attrgetter only when you need the attribute itself, not a call.
Reading it
- Direct calls win when the method name is static.
methodcalleris for higher-order tools (map,sorted(..., key=methodcaller("lower"))) — readable, slight tax.getattr+call suits truly dynamic names; expect overhead vs direct.- Pre-binding helps if you call the same bound methods repeatedly; binding every iteration loses.
Pitfalls
- Using methodcaller where a direct call is fine (noise in profiles).
- Binding methods in a tight loop without reuse.
- Confusing attrgetter (get attribute) with methodcaller (call method).
- Passing wrong arity into methodcaller-bound args.
- Measuring only n=1k — check a larger size before drawing product conclusions.
Reproduce
Evidence: summary.json, summary.txt.
Limits
One Linux box. Microbench only — real workloads with I/O will dwarf call overhead. Tiny methods returning ints. Not free-threaded surprises. Not slots vs dict object layouts beyond Widget slots.
Takeaway
At 10 k objects, direct ~30.38 Mcalls/s beat getattr ~17.04 and methodcaller ~13.53. Prefer direct in hot loops; methodcaller when you need a portable callable for APIs that expect a function.
Lab evidence
What I found running this
Lab 1 Oct 2026 IST. Python 3.13.5. n=10k value(): direct 30.38 Mcalls/s; getattr 17.04; methodcaller 13.53; prebound 29.68. Not attrgetter/itemgetter. Affiliates: 0. Evidence: lab-evidence/99-methodcaller-vs-getattr/.
Related links
Plate 12
islice vs list Slice Windows: Localhost Lab
Hands-on itertools.islice vs list slice window lab: real ops/s taking ranges from sequences, measured on Linux localhost in this hands-on lab for SREs.
Observability & SRE · 1 Oct 2026
Plate 07
heapq.merge vs sorted(chain): Localhost Lab
Hands-on heapq.merge vs sorted(chain) multi-way merge: real records/s on pre-sorted lists, measured on Linux localhost today in this hands-on lab for SREs.
Observability & SRE · 1 Oct 2026
Plate 88
mmap Write vs pwrite Region: Localhost Lab
Hands-on mmap MAP_SHARED write+msync vs pwrite region update: real MB/s with durability labels, measured on Linux localhost in this hands-on lab for SREs.
Observability & SRE · 1 Oct 2026