簡體   English   中英

使用上下文管理器發生異常時的Python替代分配

[英]Python alternative assignment when exceptions occur using context manager

在Python中,如果對該變量的第一次分配引發異常,則可以為該變量分配替代值,例如:

try:
    a = 1/0
except Exception:
    a = 0

我想知道我們可以用上下文管理器替換try/except嗎?

這是我嘗試的:

from contextlib import contextmanager

@contextmanager
def tryo(*exception_list):
    t = tuple(i for i in exception_list[0]
              if isinstance(i,Exception) or (Exception,))
    try:
        yield
    except t as e:
        print e

with tryo([(Exception, 0)]):
    a = 1/0

我想我必須做些事情而不是yield但不知道該怎么辦。 有什么建議嗎?

異常(在這種情況下為ZeroDivisionError )不是由分配失敗引起的,而是由於被0

第一個代碼可以如下轉換:

a = 0
try:
    a = 1 / 0
except Exception:  # ZeroDivisionError:
    pass

如何使用以下方法(生成默認值, with語句主體更改該值)?

>>> from contextlib import contextmanager
>>>
>>> @contextmanager
... def tryo(exceptions, default):
...     try:
...         yield default
...     except exceptions:
...         pass
...
>>> with tryo((Exception), 0) as a:  # ZeroDivisionError:
...     a = 1 / 0
...
>>> with tryo((Exception), 0) as b:  # ZeroDivisionError:
...     b = 4 / 2
...
>>> a
0
>>> b
2.0

上下文管理器無法知道您在上下文中正在做什么。 尤其是,它無法分辨出您要向哪個變量賦值; 它也將無法訪問該變量; 即使可以,也無法保證您也只能在上下文管理器中進行一次分配。 所以,不,你不能那樣做。

但是,您可以做的是另一種方法。 您的0是默認值,因此您應將其設置為first 之后,您嘗試分配實際值1/0並忽略ZeroDivisionError。 所以它看起來像這樣:

a = 0
try:
    a = 1/0
except ZeroDivisionError:
    pass

而且您可以使用contextlib.suppress使用上下文管理器進行操作:

a = 0
with suppress(ZeroDivisionError):
    a = 1/0

您可以像這樣使用Decorator:

def my_decorator(exception_list):
    def real_decorator(func):
        def fn_wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except tuple(e for e, _ in exception_list) as e:
                for error, default in exception_list:
                    if isinstance(e, error):
                        return default
                else:
                    # this Exception not in exception_list
                    raise e
        return fn_wrapper
    return real_decorator


@my_decorator([(ZeroDivisionError, 1),
               (IndexError, 2),
               (ValueError, 3),
               (Exception, 0)],
              )
def div_working():
    import random
    e = random.choice((ZeroDivisionError, IndexError, ValueError, Exception, 100, 200, 300))
    if isinstance(e, int):
        return e
    else:
        print e
        raise e

for _ in range(10):
    a = div_working()
    print a
    print "= " * 10

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM