Open
Description
Easier to Ask Forgiveness than Permission (EAFP) style recently added to some of the python interfaces, see e.g. https://github.com/FEniCS/dolfinx/blob/main/python/dolfinx/la/petsc.py#L130 leads to
- large performance overhead, see example below and,
- opaque error handling. If any of the deep nested try/except blocks fails then user sees the outer exception caught which looks like an error message, but is not an error. The logic in the code also depends on the type of exception caught thus relies on the code being called raising consistently.
The following benchmark
import time
import platform
import datetime
import textwrap
import numpy as np
N = 1_000_000
def eafp():
total = 0
for k in range(N):
try:
raise RuntimeError
except RuntimeError:
try:
raise RuntimeError
except RuntimeError:
total += k
return total
def lbyl():
total = 0
for k in range(N):
if isinstance(k, ()):
pass
else:
if isinstance(k, ()):
pass
else:
total += k
return total
def run_benchmark(fn, repeats=3):
times = []
for _ in range(repeats):
start = time.perf_counter()
fn()
times.append(time.perf_counter() - start)
times = np.array(times)
mean = times.mean()
std = times.std()
return mean, std # use best-of-repeats to reduce noise
lbyl_time_mean, lbyl_time_std = run_benchmark(lbyl)
eafp_time_mean, eafp_time_std = run_benchmark(eafp)
benchmark_info = textwrap.dedent(f"""
Python {platform.python_version()} on {platform.python_implementation()}
Date: {datetime.datetime.now().isoformat(sep=" ", timespec="seconds")}
Iterations : {N:,}
RESULTS
------------------------
EAFP (try/except) : mean {eafp_time_mean:.4f} s, std {eafp_time_std:.4f} s
LBYL (isinstance) : mean {lbyl_time_mean:.4f} s, std {lbyl_time_std:.4f} s
Speed-up (LBYL/EAFP) : mean {eafp_time_mean / lbyl_time_mean:.1f} × faster
""")
print(benchmark_info)
executes for me in dolfin/dolfinx:nightly on M4 as
Python 3.12.3 on CPython
Date: 2025-05-20 13:51:58
Iterations : 1,000,000
RESULTS
------------------------
EAFP (try/except) : mean 0.1267 s, std 0.0017 s
LBYL (isinstance) : mean 0.0287 s, std 0.0001 s
Speed-up (LBYL/EAFP) : mean 4.4 × faster
In my opinion EAFP should only be used when we expect a small number of misses (miss == exception being caught), and without double try/except clause.
Metadata
Metadata
Assignees
Labels
No labels