120

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

就像是...

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

b声明变量在哪里而c不是......所以c会抛出错误并a变成b......

4

15 回答 15

89

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

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 。

于 2011-11-09T06:26:30.380 回答
89

在 python3 中,您可以使用contextlib.suppress

from contextlib import suppress

d = {}
with suppress(KeyError): d['foo']
于 2018-08-25T19:17:50.713 回答
72

在 Python中没有办法将try/except块压缩到一行中。

此外,不知道 Python 中是否存在变量是一件坏事,就像在其他一些动态语言中一样。更安全的方法(和流行的风格)是将所有变量设置为某个值。如果它们可能没有被设置,请将它们设置为Nonefirst (或者0''如果它更适用,则设置为其他东西。)


如果您确实首先分配了您感兴趣的所有名称,那么您确实可以选择。

  • 最好的选择是 if 语句。

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

    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]因为[]在布尔上下文中为假。因为有很多值可能是假的,所以我不使用这个or技巧。(这与人们说if foo:他们的意思时遇到的问题相同if foo is not None:。)

于 2010-03-26T16:26:17.867 回答
19

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
于 2019-05-14T19:21:18.810 回答
17

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

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

于 2017-08-23T13:25:45.487 回答
10

问题是它实际上是我正在尝试测试的 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等。

于 2017-10-01T20:51:28.880 回答
7
parse_float = lambda x, y=exec("def f(s):\n try:\n  return float(s)\n except:  return None"): f(x)

总是有解决办法的。

于 2018-01-22T01:41:05.490 回答
7

用两条线怎么样。可以吗?

>>> try: a = 3; b= 0; c = a / b
... except : print('not possible'); print('zero division error')
...
not possible
zero division error
于 2020-04-08T03:21:06.707 回答
5

在 Python3 上工作,灵感来自 Walter Mundt

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

将多行合并为一行

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

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

于 2020-01-15T07:12:30.577 回答
4

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

>>> b = 'some variable'
>>> a = vars().get('c', b)
于 2010-03-26T18:02:07.593 回答
2

你提到你正在使用 django。如果它对你正在做的事情有意义,你可能想要使用:

my_instance, created = MyModel.objects.get_or_create()

created将是真或假。也许这会对你有所帮助。

于 2010-03-26T16:44:45.580 回答
2

这是@surendra_ben 提供的答案的更简单版本

a = "apple"
​
try: a.something_that_definitely_doesnt_exist
except: print("nope")

...

nope
于 2020-11-24T01:22:42.283 回答
2

with在一行中使用语法:

class OK(): __init__ = lambda self, *isok: setattr(self, 'isok', isok); __enter__ = lambda self: None; __exit__ = lambda self, exc_type, exc_value, traceback: (True if not self.isok or issubclass(exc_type, self.isok) else None) if exc_type else None

忽略任何错误:

with OK(): 1/0

忽略指定的错误:

with OK(ZeroDivisionError, NameError): 1/0
于 2021-01-05T13:46:13.903 回答
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
于 2018-05-08T04:10:47.777 回答
0

The two-liner version doesn't work me. I use VSCode on ubuntu 20.04 x64.It only works if I move the exception statements to a new line. The try can remain a single line. So minimally I would need 3 lines. Don't know if this is a bug or feature.

于 2021-10-19T11:01:47.480 回答