

以下のコードでlocalという変数に格納されたアドレスにある圧縮ファイルを解凍しようとした場合に、もしもlocalという圧縮ファイルが存在せず、FileNotFoundErrorが発生したらlocalに対する処理を飛ばしたいです。  
どのように以下のコードを変えれば上の問題は解決するでしょうか...?

コード

[code]

    # coding: utf-8
    import zipfile
    
    local = 'local.zip'
    with zipfile.ZipFile(local, 'r') as zf: #zipファイルを読む。ファイルが見つからない時の例外処理はどうすれば...。
        files = [info.filename for info in zf.infolist() if info.filename.endswith('.txt')]
    
[/code]


CC BY-SA 4.0
2018-12-27T11:17:27.867
51563
2022-06-15T16:55:10.057
2022-06-15T16:55:10.057
31249
31249
question
python python3 exception
with文で例外が発生した場合に、処理を飛ばす方法


### withブロック内で特定の例外が起きた際にwithブロックから出る

[`contextlib.suppress`](https://docs.python.jp/3/library/contextlib.html#contextlib.suppress)
が使えます。

[code]

    #!/usr/bin/python3
    import zipfile
    from contextlib import suppress
    
    with suppress(FileNotFoundError):
        with zipfile.ZipFile("file.zip", 'r') as zf:
            print("success:", zf)   # 何らかの処理
    
[/code]

このようなネストした[with文](https://docs.python.jp/3/reference/compound_stmts.html#with)は一つにしてインデントを減らせます。

[code]

    with suppress(FileNotFoundError), zipfile.ZipFile("file.zip", 'r') as zf:
        print("success:", zf)   # 何らかの処理
    
[/code]

### コンテキスト式の例外のみ捕える

上ではwithブロック内で発生した例外（`FileNotFoundError`）全てを捕えています。そうでは無く、コンテキスト式 （今回の例では
`zipfile.ZipFile` でファイルを開く部分）での例外のみを処理したい場合は
[`contextlib.ExitStack`](https://docs.python.jp/3/library/contextlib.html#contextlib.ExitStack)
が使えます。

[code]

    from contextlib import ExitStack
    # 略
    # for 文の末尾であるとして、 with ブロックから continue で脱出
    with ExitStack() as stack:
        try:
            zf = stack.enter_context(zipfile.ZipFile("file.zip", 'r'))
        except FileNotFoundError:
            continue
        print("success:", zf)   # 何らかの処理
    
[/code]

### 任意の箇所でwithブロックから抜ける

上ではwith文がfor文の末尾にあるものとし、`continue` でwith文を抜けています。他にも例えば関数の末尾であれば `return`
が使えます。しかし、with文がそういった箇所に置かれていない場合もあります。その際は、上で紹介した
[`contextlib.suppress`](https://docs.python.jp/3/library/contextlib.html#contextlib.suppress)
を組み合わせるとよいのではと思います。

[code]

    #!/usr/bin/python3
    import zipfile
    from contextlib import suppress, ExitStack
    
    class SkipError(Exception):
        pass
    
    with suppress(SkipError), ExitStack() as stack:
        try:
            zf = stack.enter_context(zipfile.ZipFile("file.zip", 'r'))
        except FileNotFoundError:
            raise SkipError("zip file not found")
    
        print("success:", zf)   # 何らかの処理
    
[/code]

他にも公式ドキュメントの[「`__enter__`
メソッドからの例外をキャッチする」](https://docs.python.jp/3/library/contextlib.html#catching-
exceptions-from-enter-methods) などが参考になります。


CC BY-SA 4.0
2018-12-30T08:43:48.680
51618
2018-12-30T08:52:31.740
2018-12-30T08:52:31.740
3054
3054
51563
answer