62

是否可以在 lambda 函数中使用 try catch 块。我需要 lambda 函数将某个变量转换为整数,但并非所有值都能够转换为整数。

4

5 回答 5

96

没有。Python lambda 只能是一个表达式。使用命名函数。

写一个泛型函数来转换类型很方便:

def tryconvert(value, default, *types):
    for t in types:
        try:
            return t(value)
        except (ValueError, TypeError):
            continue
    return default

然后你可以写你的 lambda:

lambda v: tryconvert(v, 0, int)

您也可以编写tryconvert()返回一个接受要转换的值的函数;那么你不需要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

现在tryconvert(0, int)返回一个函数,该函数convert_0_int接受一个值并将其转换为整数,0如果无法完成则返回。您可以立即使用此功能(不保存副本):

mynumber = tryconert(0, int)(value)

或者保存它以便以后调用它:

intconvert = tryconvert(0, int)
# later...
mynumber = intconvert(value)
于 2012-09-16T23:23:24.340 回答
38

在这种特定情况下,您可以避免使用这样的try块:

lambda s: int(s) if s.isdigit() else 0

如果的所有字符都是数字,则isdigit()string 方法返回 true 。(如果您需要接受负数,则必须进行一些额外的检查。)s

于 2012-09-16T23:25:15.647 回答
5

是的,有可能

我把这段小代码放在一起来演示捕获异常并在 lambda 中对它们做出反应的可能性。它相当初级,或多或少地用作概念证明。

例子

>>> 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.

一个更实际的例子

modules = filter(None, (
  begin(importlib.import_module, modname).rescue(lambda exc: None)()
  for modname in module_names
))


代码

from typing import Iterable

class 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)
于 2020-02-28T21:31:38.833 回答
1

根据您的需要,另一种方法可能是将 try:catch 保持在 lambda fn 之外

toint  = lambda x : int(x)
strval = ['3', '']

for s in strval:
    try:
        print 2 + toint(s)
    except ValueError:
        print 2

输出:

5
2
于 2015-09-09T12:15:15.173 回答
0

虽然没有通用的方法来处理 lambda 表达式中的异常,但您可以针对至少一种异常以受限的方式实现它;StopIteration从表达式的一部分抛出 a并在另一部分捕获它是可以实现的;看:

from random import randrange

list((lambda:(yield from (randrange(0,2) or next(iter(())) for _ in (None,))))())

在哪里next(iter(()))举起StopIteration一会儿yield from就会抓住它;上面的表达式随机返回[][1]根据内部随机值(a0将引发异常并且 a1将被正常评估)。

您可以通过http://baruchel.github.io/python/2018/06/20/python-exceptions-in-lambda/了解更多信息。

于 2018-06-21T06:33:55.213 回答