Today
-
Yesterday
-
Total
-
  • Python3 with catch
    Programming Language/Python3 2021. 10. 25. 19:01

    with statement

    python에서 with문을 사용하는 것은 파일을 읽을 때, 장점이 있다.

     

    with open("./note.txt") as f:
        text = f.read()
        # f.close()

     

    with문이 종료할 때 별도로 .close()를 하지 않아도 종료해주기 때문에 안전하게 파일에 접근할 수 있다.
    그렇다면 내 생각엔 with문으로 파일을 읽는 동안 발생하는 에러에 대해서 with except문같은 구문이 있지 않을까 생각했다.

     


    결론

    결론부터 말하면, 그러한 문법은 존재하지 않았다.
    아래의 답변은 with문을 try로 감싸거나, 파일을 열 때 try로 감싸고 그 후 에러가 없는 경우 with를 쓰는 코드를 보여주고 있다.

    1. try-with
    from __future__ import with_statement
    
    try:
        with open( "a.txt" ) as f :
            print f.readlines()
    except EnvironmentError: # parent of IOError, OSError *and* WindowsError where available
        print 'oops'
    1. try open-else with
    try:
        f = open('foo.txt')
    except IOError:
        print('error')
    else:
        with f:
            print f.readlines()

     

    내 결론

    난 위의 방법이 아닌 그저 with문을 안쓰는 쪽을 선택했다.

     


     

    Deep dive

    그런데 아직도 이상하다. 왜 지원해주지 않는걸까?


    stackoverflow catching-an-exception-while-using-a-python-with-statement에서 a_guest의 답변에 따르면 ContextManager때문이라고 한다.

     

    자세한 내용까지는 다 이해하지 못했지만, 개략적으로 이야기하자면 ContextManager의 동작방식때문이라고 한다. PEP 343의 예시에 따르면 아래의 코드와 with문이 동일한 형태라고 한다.

     

    import sys
    
    try:
        mgr = ContextManager()
    except ValueError as err:
        print('__init__ raised:', err)
    else:
        try:
            value = type(mgr).__enter__(mgr)
        except ValueError as err:
            print('__enter__ raised:', err)
        else:
            exit = type(mgr).__exit__
            exc = True
            try:
                try:
                    BLOCK
                except TypeError:
                    pass
                except:
                    exc = False
                    try:
                        exit_val = exit(mgr, *sys.exc_info())
                    except ValueError as err:
                        print('__exit__ raised:', err)
                    else:
                        if not exit_val:
                            raise
            except ValueError as err:
                print('BLOCK raised:', err)
            finally:
                if exc:
                    try:
                        exit(mgr, None, None, None)
                    except ValueError as err:
                        print('__exit__ raised:', err)

     

    코드에서는 아래와 같은 경우에서 raise가 발생한다. (코드에서는 print로 표시되어 있다.)

    • ContextManager.__init__
    • ContextManager.__enter__
    • the body of the with
    • ContextManager.__exit__

     

    with-except를 쓸 수 없는 이유는 raise가 여러 곳에서 발생하기 때문이라고 이해했다.
    물론 except로 발생하는 모든 예외를 잡을 수 있을 것이다. 하지만 그것은 잘못된 표현법이다.


    왜냐하면 외부에서 봤을 때 with문은 한줄이기 때문에 하나의 뎁스?의 코드가 동작하고 반환되는 것 같지만 실제로는 여러 뎁스의 동작이 존재하기 때문에 명시적으로 with-except문을 사용하게 되면, 사용자는 with에서 발생한 에러에 대해 추상적으로 판단하게 될 것이다.

     

    어쨌든 with문은 굉장히 추상화되어 있는 구문이다.
    좋은 표현법이라고 하기 어렵겠다.

     


    References

    'Programming Language > Python3' 카테고리의 다른 글

    "private" in python  (0) 2021.10.25
    `pipenv`는 정말 좋다.  (0) 2021.10.25
    파이썬 내부 클래스에 대해  (0) 2021.10.25
    Pytest에 대해 알아보자.  (0) 2021.10.25
    [번역] Pytest fixture  (0) 2021.10.25

    댓글

Designed by Tistory.