Python:单行中的try语句


89

python中有没有办法将try / except变成一行?

就像是...

b = 'some variable'
a = c | b #try statement goes here

哪里b是声明的变量,c而不是...所以c会引发错误并a变成b...

Answers:


60

在Python中,无法将try/except块压缩到一行上。

另外,不知道变量是否像在其他动态语言中一样,在Python中是否存在也是一件坏事。比较安全的方法(和流行的样式)是将所有变量设置为某种值。如果他们可能就不会置,将其设置为None第一(或0''或如果它是更适用的东西。)


如果确实要分配所有您感兴趣的名称,则可以选择。

  • 最好的选择是if语句。

    c = None
    b = [1, 2]
    
    if c is None:
        a = b
    else:
        a = c
    
  • 单线选项是一个条件表达式。

    c = None
    b = [1, 2]
    a = c if c is not None else b
    
  • 有些人滥用or这样做的短路行为。这容易出错,所以我从不使用它。

    c = None
    b = [1, 2]
    a = c or b
    

    考虑以下情况:

    c = []
    b = [1, 2]
    a = c or b
    

    在这种情况下,a可能应该[],但这是[1, 2]因为[]在布尔上下文中为false。因为有很多可能为假的值,所以我不使用or技巧。(这是人们在表达if foo:自己的意思时遇到的相同问题if foo is not None:。)


谢谢。问题是它实际上是我正在尝试测试的django model.objects.get查询。如果没有找到数据,.get将返回错误...它不会返回None(这使我很烦)
Brant Brant

@Brant,好吧,这种情况与检查是否设置了变量(在Python中没有声明变量)有点不同。Python中的典型样式是更喜欢引发异常,而不是将错误作为值返回,这是我们许多人真正喜欢的。每次都要检查一个操作的返回码,并且如果我不这样做就很难追踪错误,这在编写Python时我绝对不会错过C。无论如何,尽管已经讨论过,但try/except块没有单行语法。幸运的是,线路便宜,因此4线解决方案应该可以为您服务。;-)
Mike Graham 2010年

它是字典中大量元组的一部分...我只是想将其缩短一点
Brant

2
get如果您不想例外,请不要使用。使用filter代替。
jcdyer

@MikeGraham好的答案-一个提示(链接?)为什么短路容易出错。
kratenko 2014年

83

这非常骇人听闻,但是当我想编写一系列调试动作时,已经在提示符下使用了它:

exec "try: some_problematic_thing()\nexcept: problem=sys.exc_info()"
print "The problem is %s" % problem[1]

在大多数情况下,我完全不受no-single-line-try-except限制的困扰,但是当我只是做实验时,我希望readline在交互式解释器中一次调用全部代码,因此我可以以某种方式调整它,这个小技巧很有用。

对于您要实现的实际目的,您可以尝试locals().get('c', b);理想情况下,最好使用真实的字典而不是本地上下文,或者只在运行可能设置或未设置它之前将c分配给None。


26
嘿,这回答了问题!:)
史蒂夫·贝内特

4
喜欢这个答案,超级混乱,但是只有一行,就像我喜欢的那样。
Patrick Cook

这就是答案!!将problem[0]返回该函数返回的内容?
SIslam

4
Exec是一种代码气味,应避免使用,除非其他方法无效。如果一行代码非常重要,那么这将起作用,但是您需要问自己为什么一行如此重要。
Gewthen

4
显然不是用于生产用途,而是用于笨拙的调试会话所需的内容。
ThorSummoner '16


13

另一种方法是定义上下文管理器:

class trialContextManager:
    def __enter__(self): pass
    def __exit__(self, *args): return True
trial = trialContextManager()

然后使用该with语句在一行中忽略错误:

>>> with trial: a = 5      # will be executed normally
>>> with trial: a = 1 / 0  # will be not executed and no exception is raised
>>> print a
5

如果发生运行时错误,则不会引发异常。就像try:没有了except:


1
这很棒!由于没有显式的try / except,您能否简要说明上下文管理器如何处理错误?
Patrick

8

poke53280答案的版本,带有有限的预期例外。

def try_or(func, default=None, expected_exc=(Exception,)):
    try:
        return func()
    except expected_exc:
        return default

它可以用作

In [2]: try_or(lambda: 1/2, default=float('nan'))
Out[2]: 0.5

In [3]: try_or(lambda: 1/0, default=float('nan'), expected_exc=(ArithmeticError,))
Out[3]: nan

In [4]: try_or(lambda: "1"/0, default=float('nan'), expected_exc=(ArithmeticError,))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
[your traceback here]
TypeError: unsupported operand type(s) for /: 'str' and 'int'

In [5]: try_or(lambda: "1"/0, default=float('nan'), expected_exc=(ArithmeticError, TypeError))
Out[5]: nan

“ expected_exc =(Exception,)”中的逗号是什么?你能解释一下吗?
伊比尔根


5

问题是它实际上是我正在尝试测试的django model.objects.get查询。如果没有找到数据,.get将返回错误...它不会返回None(这使我很烦)

使用这样的东西:

print("result:", try_or(lambda: model.objects.get(), '<n/a>'))

其中try_or是您定义的实用程序函数:

def try_or(fn, default):
    try:
        return fn()
    except:
        return default

您也可以选择限制接受的异常类型NameErrorAttributeError等等。


4

您可以通过访问该命名空间字典做到这一点vars()locals()或者globals(),无论哪个是最适合您的情况。

>>> b = 'some variable'
>>> a = vars().get('c', b)

3
这与检查是否设置了变量并不完全相同(尽管如果您对特定范围感兴趣,也可以这样做)。此外,ewwwwwwww ..
Mike Graham 2010年

4

如何使用两行。可以吗?

>>> try: a = 3; b= 0; c = a / b
... except : print('not possible'); print('zero division error')
...
not possible
zero division error

2

您提到您正在使用django。如果您的工作有意义,则可以使用:

my_instance, created = MyModel.objects.get_or_create()

created将为True或False。也许这会对您有所帮助。


1

如果您需要实际管理异常:(
从poke53280的答案中修改)

>>> def try_or(fn, exceptions: dict = {}):
    try:
        return fn()
    except Exception as ei:
        for e in ei.__class__.__mro__[:-1]:
            if e in exceptions: return exceptions[e]()
        else:
            raise


>>> def context():
    return 1 + None

>>> try_or( context, {TypeError: lambda: print('TypeError exception')} )
TypeError exception
>>> 

请注意,如果不支持该异常,它将按预期引发:

>>> try_or( context, {ValueError: lambda: print('ValueError exception')} )
Traceback (most recent call last):
  File "<pyshell#57>", line 1, in <module>
    try_or( context, {ValueError: lambda: print('ValueError exception')} )
  File "<pyshell#38>", line 3, in try_or
    return fn()
  File "<pyshell#56>", line 2, in context
    return 1 + None
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
>>> 

如果Exception给出,它将与下面的任何内容匹配。
BaseException更高,因此将不匹配)

>>> try_or( context, {Exception: lambda: print('exception')} )
exception

1

在Walter Mundt的启发下在Python3上工作

exec("try:some_problematic_thing()\nexcept:pass")

对于多行成一行

exec("try:\n\tprint('FirstLineOk')\n\tsome_problematic_thing()\n\tprint('ThirdLineNotTriggerd')\nexcept:pass")

附言:Exec在无法控制的数据上使用是不安全的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.