【问题标题】:Python Try Catch Block inside lambdaPython 在 lambda 中尝试 Catch 块
【发布时间】:2023-03-15 02:22:01
【问题描述】:

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

【问题讨论】:

标签: python lambda try-catch


【解决方案1】:

不。 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)

【讨论】:

    【解决方案2】:

    是的,有可能

    我整理了这段小代码来演示捕获异常并在 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)
    

    【讨论】:

      【解决方案3】:

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

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

      next(iter(())) 引发StopIterationyield from 将捕获它;上面的表达式根据内部随机值随机返回[][1]0 将引发异常,1 将正常计算)。

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

      【讨论】:

        【解决方案4】:

        根据您的需要,另一种方法可能是将 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
        

        【讨论】:

          【解决方案5】:

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

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

          如果s所有字符都是数字,则isdigit() string method 返回true。 (如果你需要接受负数,你将不得不做一些额外的检查。)

          【讨论】:

          • 曾在 re.search 上尝试过同样的逻辑,效果很好。单线很漂亮。
          • 这不适用于诸如 5.5 之类的值,这些值是有效输入,但对于 .isdigit() 不返回 True。
          • @Modelmat:这个问题专门询问整数
          • 它要求将某个值转换为整数。这没有指定该值是否必须是整数才有效。此外,这个特定的值甚至没有必须是一个字符串。尽管如此,了解它仍然很有用。
          猜你喜欢
          • 1970-01-01
          • 2010-12-25
          • 1970-01-01
          • 2023-03-18
          • 1970-01-01
          • 2015-10-07
          • 2021-11-26
          • 2013-01-01
          • 2022-06-10
          相关资源
          最近更新 更多