Python Try Catch Block inside lambda
Nope. A Python lambda can only be a single expression. Use a named function.
It is convenient to write a generic function for converting types:
def tryconvert(value, default, *types): for t in types: try: return t(value) except (ValueError, TypeError): continue return default
Then you can write your lambda:
lambda v: tryconvert(v, 0, int)
You could also write tryconvert()
so it returns a function that takes the value to be converted; then you don't need the lambda:
def tryconvert(default, *types): def convert(value): for t in types: try: return t(value) except (ValueError, TypeError): continue return default # set name of conversion function to something more useful namext = ("_%s_" % default) + "_".join(t.__name__ for t in types) if hasattr(convert, "__qualname__"): convert.__qualname__ += namext convert.__name__ += namext return convert
Now tryconvert(0, int)
returns a function convert_0_int
that takes a value and converts it to an integer, and returns 0
if this can't be done. You can use this function right away (not saving a copy):
mynumber = tryconert(0, int)(value)
Or save it to call it later:
intconvert = tryconvert(0, int)# later...mynumber = intconvert(value)
In this specific instance, you can avoid using a try
block like this:
lambda s: int(s) if s.isdigit() else 0
The isdigit()
string method returns true if all the characters of s
are digits. (If you need to accept negative numbers, you will have to do some extra checking.)
Yes, it is possible
I put together this little piece of code to demonstrate the possibility to catch exceptions and react to them inside a lambda. It's rather rudimentary and serves more or less as a proof of concept.
Example
>>> print_msg = lambda msg, **print_kwargs: \... begin(... print, msg, end='... ', **print_kwargs... ).\... rescue(... (TypeError, AttributeError),... lambda exc: print(f'just caught "{exc}"! how fun!')... ).\... ensure(print, 'ok done.')()>>> print_msg('check')check... ok done.>>> print_msg('check', file=1)just caught "'int' object has no attribute 'write'"! how fun!ok done.>>> print_msg('check', sep=1)just caught "sep must be None or a string, not int"! how fun!ok done.
A bit more practical example
modules = filter(None, ( begin(importlib.import_module, modname).rescue(lambda exc: None)() for modname in module_names))
Code
from typing import Iterableclass begin: def __init__(self, fun, *args, **kwargs): self.fun = fun self.args = args self.kwargs = kwargs self.exception_types_and_handlers = [] self.finalize = None def rescue(self, exception_types, handler): if not isinstance(exception_types, Iterable): exception_types = (exception_types,) self.exception_types_and_handlers.append((exception_types, handler)) return self def ensure(self, finalize, *finalize_args, **finalize_kwargs): if self.finalize is not None: raise Exception('ensure() called twice') self.finalize = finalize self.finalize_args = finalize_args self.finalize_kwargs = finalize_kwargs return self def __call__(self): try: return self.fun(*self.args, **self.kwargs) except BaseException as exc: handler = self.find_applicable_handler(exc) if handler is None: raise return handler(exc) finally: if self.finalize is not None: self.finalize() def find_applicable_handler(self, exc): applicable_handlers = ( handler for exception_types, handler in self.exception_types_and_handlers if isinstance(exc, exception_types) ) return next(applicable_handlers, None)