Python:try-except作为表达式?

时间:2011-08-17 04:36:36

标签: python

我发现自己一遍又一遍地拥有这种模式:

variable = ""
try:
    variable = ... do some file loading stuff ...
except:
    variable = ""

有没有办法将它压缩成单个表达式?与if-else语句一样,您可以转向:

variable = ""
if something:
    variable = somethingelse
else:
    variable = ""

variable = somethingelse if something else ""

try-catch有没有相同的东西?

7 个答案:

答案 0 :(得分:18)

由于agf已经提供了我推荐的方法,这里是他的例程的一个版本,有一些小的改进:

def try_except(success, failure, *exceptions):
    try:
        return success()
    except exceptions or Exception:
        return failure() if callable(failure) else failure

此版本:

  1. 允许您准确指定将作为附加可选参数捕获的异常。您应始终捕获将执行此任务的最小异常集,并让您无法处理的异常冒泡到调用方。

  2. 支持使用普通值以及故障值的函数。这可以节省您在很多情况下使用lambda的麻烦。 (当然,您可以使用lambda: ''代替str。)

答案 1 :(得分:14)

def try_except(success, failure):
    try:
        return success()
    except:
        return failure()

variable = try_except(do_some_file_loading_stuff, lambda: '')

我认为代码是自我解释的。它返回success返回的值,除非出现错误,然后返回failure返回的值。如果do_some_file_loading_stuff是表达式而不仅仅是函数调用,那么也将它包装在lambda中。

编辑: @kindall和我改进了他的版本,所以它和我一样快,如果你想要的话可​​以完全相同,有更多的功能,并且行数相同。使用它!

def try_except(success, failure, *exceptions):
    try:
        return success()
    except exceptions or Exception:
        return failure() if callable(failure) else failure

答案 2 :(得分:12)

这是一个提供一点快捷方式的上下文管理器:

from contextlib import contextmanager

@contextmanager
def catch(*exceptions, **kwargs):
    try:
        yield kwargs.get("default", None)
    except exceptions or Exception:
        pass

用法:

with catch(ZeroDivisionError, default=0) as x:
    x = 3 / 0              # error

print x                    # prints 0, the default

这里的基本思想是上下文管理器返回您传递的任何默认值,然后将其分配给您在with语句的as子句中指定的变量。然后,在上下文中,执行一个尝试分配给同一个变量的语句。如果它引发异常,则上下文管理器会捕获并静默忽略它,但由于分配没有发生,因此默认值仍然存在。

对于多行计算可能特别有用,但仍会产生单个值。

答案 3 :(得分:3)

不幸的是,不,没有语言构造,我也不知道任何真正清晰简洁的习语。我一直想要那样的东西。前段时间有人给我理由,Python没有类似variable = function_cal() except ""的东西,但它们不是很有说服力,我仍然想念这种语言结构:)

答案 4 :(得分:1)

显然,后一种做法更加简洁,是像你这样的许多程序员的首选。

虽然语言本身没有提供“一线尝试 - 除了捕获”,无论出于什么原因,一切都是好的和必要的,我认为,你通常可以通过改变程序来做到这一点;例如:

try:
    a_var = a_dict.get('abcd')
except a_dict.KeyError:
    a_var = ''

成:

a_var = a_dict.get('abcd',default='')

,类似于数据库查询;

try:
    a_qs = Model.objects.get(id=42)
except Model.DoesNotExist:
    a_qs = Model.objects.create(id=42)

a_qs = Model.objects.get_or_create(id=42,**kwargs)

并尽可能将类似的API添加到您自己的程序中。 try-except在Python中相当“便宜”,并且由于异常处理的昂贵性质,基于异常的编程比Java语言中通常建议的“先检查”方法更受欢迎。所以,你应该在方法/函数中包装这个“捕捉事物”并在每个地方调用它,例如dict和其他结构。

答案 5 :(得分:0)

没有简单的方法来简化try / catch语句,比如if / else示例,但是我想指出python2.5中引入的python的“with”语句使得很多接口到文件/ db io试试catch语句更简单,异常安全。 IO操作往往是使用大量try / catch语句的地方。

with open("myfile.txt", "r") as f:
   # Do stuff with f

而不是

try:
   f = open("myfile.txt", "r")
   # Do stuff with f
except:
   pass
finally:
   if f: f.close

答案 6 :(得分:0)

with-handlers in Racket的启发:

def with_handlers(handlers: Dict[Type[Exception], Callable[[Exception], S]], f: Callable[[], T]) -> Union[S, T]:
    try:
        return f()
    except tuple(handlers.keys()) as err:
        return handlers[type(err)](err)

handlers包含所有预期的异常及其相应的处理程序。

这是一个catch函数,它还支持else和final子句:

def catch(
        try_clause: Callable[[], T],
        except_clauses: Dict[Type[Exception], Callable[[Exception], S]],
        else_clause: Optional[Callable[[T], R]] = None,
        final_clause: Optional[Callable[[Union[T, S]], None]] = None) -> Union[R, S, T]:
    try:
        ret = try_clause()
    except tuple(except_clauses.keys()) as err:
        handled = except_clauses[type(err)](err)
        return handled
    else:
        return ret if else_clause is None else else_clause(ret)
    finally:
        if final_clause is not None:
            try:
                final_clause(ret)
            except NameError:
                final_clause(handled)

在Python中,try语句不会引入自己的作用域, 但是这里try_clause是一个函数,因此else_clause需要一个参数来接收来自try_clause的信息。 同样,final_clause需要两个参数。