I've been trying to figure out what's the best, most Pythonic way to get the first element of a sequence that matches a condition. Here are three options:
- I don't like that I've written
caller[0].f_locals.get("runner")
twice, but it feels most Pythonic otherwise.runner = next( caller[0].f_locals.get("runner") for caller in inspect.stack() if isinstance(caller[0].f_locals.get("runner"), AbstractRunner) )
- Is it weird to rely on an assignment during the loop?
for caller in inspect.stack(): runner = caller[0].f_locals.get("runner") if isinstance(runner, AbstractRunner): break
- The second line is Pythonic and all, but the first line is only there to set up a generator where you no longer have to compute the expression (only apply the conditional in the second line).
generator = (caller[0].f_locals.get("runner") for caller in inspect.stack()) runner = next(x for x in generator if isinstance(x, AbstractRunner))
There's no performance difference at all from my tests.
runner = next(runner for runner in (caller[0].f_locals.get("runner") for caller in inspect.stack()) if isinstance(runner, AbstractRunner))
. This is basically a hybrid of your first and third options. I'd consider it fairly pythonic if written out in multiple lines in a readable way. \$\endgroup\$