在 python 中有没有办法将 try/except 变成单行?
就像是...
b = 'some variable'
a = c | b #try statement goes here
b
声明变量在哪里而c
不是......所以c
会抛出错误并a
变成b
......
在 python 中有没有办法将 try/except 变成单行?
就像是...
b = 'some variable'
a = c | b #try statement goes here
b
声明变量在哪里而c
不是......所以c
会抛出错误并a
变成b
......
这是非常骇人听闻的,但是当我想编写一系列用于调试的操作时,我已经在提示符下使用了它:
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 。
在 python3 中,您可以使用contextlib.suppress:
from contextlib import suppress
d = {}
with suppress(KeyError): d['foo']
在 Python中没有办法将try
/except
块压缩到一行中。
此外,不知道 Python 中是否存在变量是一件坏事,就像在其他一些动态语言中一样。更安全的方法(和流行的风格)是将所有变量设置为某个值。如果它们可能没有被设置,请将它们设置为None
first (或者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:
。)
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
另一种方法是定义上下文管理器:
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:
.
问题是它实际上是我正在尝试测试的 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
或者,您可以将接受的异常类型限制为NameError
、AttributeError
等。
parse_float = lambda x, y=exec("def f(s):\n try:\n return float(s)\n except: return None"): f(x)
总是有解决办法的。
用两条线怎么样。可以吗?
>>> try: a = 3; b= 0; c = a / b
... except : print('not possible'); print('zero division error')
...
not possible
zero division error
在 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 在您无法控制的数据上使用是不安全的。
您可以通过使用 、 或 访问命名空间字典来做到这一点vars()
,locals()
无论globals()
哪个最适合您的情况。
>>> b = 'some variable'
>>> a = vars().get('c', b)
你提到你正在使用 django。如果它对你正在做的事情有意义,你可能想要使用:
my_instance, created = MyModel.objects.get_or_create()
created
将是真或假。也许这会对你有所帮助。
这是@surendra_ben 提供的答案的更简单版本
a = "apple"
try: a.something_that_definitely_doesnt_exist
except: print("nope")
...
nope
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
如果您需要实际管理异常:(
修改自 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
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.