파이썬 try-else


578

명령문 의 선택적 else절의 의도 된 용도는 무엇입니까 try?


1
대부분의 답변은 try 절 자체의 else 절에 자료를 넣을 수없는 이유에 집중하는 것 같습니다. 질문 stackoverflow.com/questions/3996329는 특히 else 절 코드가 try 블록 자체 이후 에 갈 수없는 이유를 묻습니다. 이 질문에 대한 답 이이 질문에 답이 없지만 여기에 해당 질문에 대한 명확한 답변이 표시되지 않습니다. stackoverflow.com/a/3996378/1503120이 그 질문에 훌륭하게 대답한다고 생각 합니다. 또한 stackoverflow.com/a/22579805/1503120 에서 다양한 절의 다양한 의미를 설명하려고 노력했습니다 .
jamadagni

최종 정리 전에 예외가 트리거되지 않으면 동일한 예외 처리를 트리거하지 않아야하는 경우가 발생합니다.
벤 지민

답변:


857

예외가없는 else경우 실행이 맨 아래로 떨어지면 블록 의 명령문 이 실행됩니다 try. 솔직히, 나는 필요를 찾지 못했습니다.

그러나 예외 처리 참고 사항 :

else 절을 ​​사용하면 try ... except 문으로 보호되는 코드에 의해 발생하지 않은 예외를 실수로 포착하지 않기 때문에 try 절에 코드를 추가하는 것보다 낫습니다.

따라서 예를 들어을 던질 수있는 메소드가 있고 IOError예외를 포착하려고하지만 첫 번째 작업이 성공 하고 IOError를 포착 하지 않으려 는 경우 다른 작업을 수행하려는 경우 해당 작업을 다음과 같이 작성할 수 있습니다.

try:
    operation_that_can_throw_ioerror()
except IOError:
    handle_the_exception_somehow()
else:
    # we don't want to catch the IOError if it's raised
    another_operation_that_can_throw_ioerror()
finally:
    something_we_always_need_to_do()

그냥 넣으면 another_operation_that_can_throw_ioerror()후에 operation_that_can_throw_ioerror는이 except두 번째 호출의 오류를 잡을 것입니다. 그리고 전체 try블록 뒤에 넣으면 항상 실행되고 finally. 은 else당신이 있는지 확인 할 수 있습니다

  1. 두 번째 작업은 예외가없는 경우에만 실행됩니다.
  2. finally블록 전에 실행 되고
  3. 어떤은 IOError그 인상이 여기 잡힌되지 않습니다에요

7
또한 try-block CAN에서 사용되는 변수는 else-block에서 사용될 수 있으므로 else-block에서 더 많은 예외를 기대하지 않는다면 항상이 변형을 사용하는 것을 고려해야합니다
WorldSEnder

3
try-scoped 변수는 다른 것이 있는지 여부에 관계없이 try 외부에서 볼 수 있기 때문에 중요하지 않습니다.
Reinderien

36
"시도 범위 변수"와 같은 것은 없습니다. 파이썬에서 변수 범위는 제어 구조가 아닌 모듈, 함수 및 이해에 의해서만 설정됩니다.
mhsmith

9
else 절을 ​​사용하면 예외가 발생하지 않은 경우에만 의미가있는 코드를 작성할 수 있습니다. except 절은 간단히 전달할 수 있습니다. 논리를 try 블록에 넣으면 코드에 자동으로 버그가 숨겨 질 위험이 있습니다. 예상치 못한 예외를 스쿼시하지 마십시오.
Alice Purcell

9
그것은 어떤이 답변에서 분명하지 않다 "바닥 떨어진다" 수단 -이 예외 상황으로 인해 발생할뿐만 아니라, 때문에의 않습니다뿐만 아니라 return, continuebreak.
Antti Haapala

108

하나가 사용에 이유 else스타일과 가독성 -. 일반적으로 코드를 처리하는 코드 근처에 예외를 일으킬 수있는 코드를 유지하는 것이 좋습니다. 예를 들어 다음을 비교하십시오.

try:
    from EasyDialogs import AskPassword
    # 20 other lines
    getpass = AskPassword
except ImportError:
    getpass = default_getpass

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
else:
    # 20 other lines
    getpass = AskPassword

두 번째는 except일찍 돌아올 수 없거나 예외를 다시 던질 때 좋습니다. 가능하다면 나는 다음과 같이 썼을 것이다.

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
    return False  # or throw Exception('something more descriptive')

# 20 other lines
getpass = AskPassword

참고 : 복사 대답 중복 최근에 게시 여기 따라서이 모든 "AskPassword"물건.


53

한 가지 용도 : 예외를 제기해야하는 일부 코드를 테스트하십시오.

try:
    this_should_raise_TypeError()
except TypeError:
    pass
except:
    assert False, "Raised the wrong exception type"
else:
    assert False, "Didn't raise any exception"

(이 코드는 실제로보다 일반적인 테스트로 추상화되어야합니다.)


50

파이썬 try-else

elsetry 문의 선택적 절의 의도 된 용도는 무엇입니까 ?

의도 된 용도는 처리 될 것으로 예상되는 예외가없는 경우 더 많은 코드를 실행할 수있는 컨텍스트를 갖는 것입니다.

이 컨텍스트는 실수로 예기치 않은 오류를 처리하지 않도록합니다.

그러나 때문에, 실행에 다른 절을 유발하는 정확한 조건을 이해하는 것이 중요합니다 return, continue그리고 break에 대한 제어 흐름을 방해 할 수 있습니다 else.

요약하자면

else이없는 경우 문이 실행 에는 예외와에 의해 중단하지 않을 경우 return, continue또는 break문.

다른 답변은 마지막 부분을 놓친 것입니다.

문서에서 :

선택적 else절은 제어 try 절의 에서 흘러 나오는 경우에 실행됩니다 . *

(볼딩이 추가되었습니다.) 그리고 각주는 다음과 같이 읽습니다.

* 현재, 제어 예외 또는 실행의 경우를 제외하고 "끝 흘러" return, continue또는 break문.

하나 이상의 선행 except 절이 필요 합니다 (grammar 참조 ). 따라서 실제로는 "시도하지 않습니다"가 아니라 "시도를 제외하고 (마지막으로)"이며 else(및 finally)는 선택 사항입니다.

파이썬 자습서 의도 된 사용에 정성 들여 :

try ... except 문은 선택적인 else 절을 ​​가지며, 존재하는 경우 모든 except 절을 따라야합니다. try 절에서 예외가 발생하지 않으면 실행해야하는 코드에 유용합니다. 예를 들면 다음과 같습니다.

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()

else 절을 ​​사용하면 try ... except 문으로 보호되는 코드에 의해 발생하지 않은 예외를 실수로 포착하지 않기 때문에 try 절에 코드를 추가하는 것보다 낫습니다.

블록을 else따르는 코드와 코드의 예try

오류를 처리하면 else블록이 실행되지 않습니다. 예를 들면 다음과 같습니다.

def handle_error():
    try:
        raise RuntimeError('oops!')
    except RuntimeError as error:
        print('handled a RuntimeError, no big deal.')
    else:
        print('if this prints, we had no error!') # won't print!
    print('And now we have left the try block!')  # will print!

그리고 지금,

>>> handle_error()
handled a RuntimeError, no big deal.
And now we have left the try block!

26

try-except-else는 EAFP 패턴오리 타이핑 을 결합 하는 데 좋습니다 .

try:
  cs = x.cleanupSet
except AttributeError:
  pass
else:
  for v in cs:
    v.cleanup()

이 순진한 코드가 괜찮을 수도 있습니다.

try:
  for v in x.cleanupSet:
    v.clenaup()
except AttributeError:
  pass

이것은 실수로 코드에 심각한 버그를 숨기는 좋은 방법입니다. 정리를 오타했지만 알려주는 AttributeError가 삼키고 있습니다. 더 나쁜 것은, 올바르게 작성했지만 정리 방법에 이름이 잘못 지정된 사용자 유형이 전달되어 중간에 자동으로 실패하고 파일을 닫지 않은 상태로 두는 경우가 있습니다. 그것을 디버깅하는 행운을 빕니다.


19

예외가있는 경우에도 정리해야 할 때 정말 유용합니다.

try:
    data = something_that_can_go_wrong()
except Exception as e: # yes, I know that's a bad way to do it...
    handle_exception(e)
else:
    do_stuff(data)
finally:
    clean_up()

9

지금은 그것을 사용할 수는 없지만 그것을 사용해야 할 수도 있습니다. 상상할 수없는 샘플은 다음과 같습니다.

else:

a = [1,2,3]
try:
    something = a[2]
except:
    print "out of bounds"
else:
    print something

없이 else:

try:
    something = a[2]
except:
    print "out of bounds"

if "something" in locals():
    print something

something오류가 발생하지 않으면 변수가 정의됩니다. 이를 try블록 외부에서 제거 할 수 있지만 변수가 정의 된 경우 지저분한 감지가 필요합니다.


3
something = a[2]; print somethingtry : 블록 내부에 어떤 문제가 있습니까?
S.Lott

@ S.Lott 아무것도 없지만 누군가가 당신에게 목록을 보내면 데이터가 손상되어 충분히 길지 않은 경우 데이터를 표시하지 않으려면 어떻게해야합니까?
알 수 없음

12
S. Lott : '뭔가 인쇄하기'는 가로 채기를 원하지 않는 다른 예외를 일으킬 수 있습니다.
다리우스 베이컨

차이가 보이지 않습니다. 범위를 벗어난 예외가 발생하면 "범위를 벗어남"이 인쇄됩니다. 알았어 다른 예외가 발생하면이 코드 블록에 의해 포착되지 않습니다. 예외가 없다면, 동작은 무언가의 값을 인쇄하는 것입니다. 그것은 [2]입니다. 이 예제에서 다른 것이 무엇인지 알 수 없습니다.
S.Lott

3
인쇄 할 때 'something'값이 __str __ () 메소드에서 오류를 일으킬 수 있습니다. 이 예제에서 해당 값은 실제로 2에 불과하지만 여기서도 경계를 벗어난 예외가 없음을 지적 할 수도 있습니다.
다리우스 베이컨

8

의 좋은 예 거기 try-elsePEP 380 . 기본적으로 알고리즘의 다른 부분에서 다른 예외 처리를 수행합니다.

다음과 같습니다.

try:
    do_init_stuff()
except:
    handle_init_suff_execption()
else:
    try:
        do_middle_stuff()
    except:
        handle_middle_stuff_exception()

이를 통해 예외가 발생한 위치에 더 가까운 예외 처리 코드를 작성할 수 있습니다.


7

에서 예외를 처리 오류 및 예외 # - docs.python.org

try ... except문은 선택 사항이 else존재하는 조항을 제외한 모든 따라야합니다, 절을. try 절에서 예외가 발생하지 않으면 실행해야하는 코드에 유용합니다. 예를 들면 다음과 같습니다.

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()

else 절을 ​​사용하면 try ... except 문으로 보호되는 코드에 의해 발생하지 않은 예외를 실수로 포착하지 않기 때문에 try 절에 코드를 추가하는 것보다 낫습니다.


6

파이썬 참조를 보면 예외가없는 else후에 실행되는 것 같습니다 try. 선택적 else 절은 제어가 try 절의 끝에서 흘러 나오는 경우에 실행됩니다. 2 else 절의 예외는 앞의 except 절에 의해 처리되지 않습니다.

파이썬으로 다이빙 하면 올바르게 이해하면 try블록에서 모듈을 가져 오려고 시도합니다. 실패하면 예외가 발생하고 기본값을 바인딩하지만 작동하면 else블록 으로 이동하여 필요한 것을 바인딩 하는 옵션 이 있습니다 (참조) 예제와 설명에 대한 링크).

catch블록 에서 작업하려고하면 다른 예외가 발생할 수 있습니다 else. 블록이 편리한 곳이라고 생각 합니다.


4
"else 절의 예외는 앞의 except 절에 의해 처리되지 않습니다." 이것이 유용한 부분입니다. 감사합니다.
geowa4

"선택적 else 절은 try 절의 끝에서 제어가 흐를 경우 실행됩니다"는 또 다른 차이점입니다. try블록에서 벗어날 수 있기 때문 입니다.
Tomer W

4

그게 다야. try-except 절의 'else'블록은 시도한 작업이 성공할 때만 실행되는 코드에 존재합니다. 사용할 수 있으며 남용 될 수 있습니다.

try:
    fp= open("configuration_file", "rb")
except EnvironmentError:
    confdata= '' # it's ok if the file can't be opened
else:
    confdata= fp.read()
    fp.close()

# your code continues here
# working with (possibly empty) confdata

개인적으로, 나는 그것을 좋아하고 필요할 때 사용합니다. 의미 적으로 구문을 그룹화합니다.


2

아마도 사용은 다음과 같습니다.

#debug = []

def debuglog(text, obj=None):
    " Simple little logger. "
    try:
        debug   # does global exist?
    except NameError:
        pass    # if not, don't even bother displaying
    except:
        print('Unknown cause. Debug debuglog().')
    else:
        # debug does exist.
        # Now test if you want to log this debug message
        # from caller "obj"
        try:
            if obj in debug:
                print(text)     # stdout
        except TypeError:
            print('The global "debug" flag should be an iterable.')
        except:
            print('Unknown cause. Debug debuglog().')

def myfunc():
    debuglog('Made it to myfunc()', myfunc)

debug = [myfunc,]
myfunc()

아마도 이것은 당신을 너무 사용하게 할 것입니다.


2

try: ... else:데이터베이스 쿼리를 실행하고 해당 쿼리 결과를 동일한 풍미 / 유형의 별도 데이터베이스에 로깅하는 상황에서 구문이 유용한 것으로 나타났습니다 . 대기열에 제출 된 데이터베이스 쿼리를 처리하는 작업자 스레드가 많이 있다고 가정 해 봅시다.

#in a long running loop
try:
    query = queue.get()
    conn = connect_to_db(<main db>)
    curs = conn.cursor()
    try:
        curs.execute("<some query on user input that may fail even if sanitized">)
    except DBError:
        logconn = connect_to_db(<logging db>)
        logcurs = logconn.cursor()
        logcurs.execute("<update in DB log with record of failed query")
        logcurs.close()
        logconn.close()
    else:

        #we can't put this in main try block because an error connecting
        #to the logging DB would be indistinguishable from an error in 
        #the mainquery 

        #We can't put this after the whole try: except: finally: block
        #because then we don't know if the query was successful or not

        logconn = connect_to_db(<logging db>)
        logcurs = logconn.cursor()
        logcurs.execute("<update in DB log with record of successful query")
        logcurs.close()
        logconn.close()
        #do something in response to successful query
except DBError:
    #This DBError is because of a problem with the logging database, but 
    #we can't let that crash the whole thread over what might be a
    #temporary network glitch
finally:
    curs.close()
    conn.close()
    #other cleanup if necessary like telling the queue the task is finished

물론 발생 가능한 예외를 구별 할 수있는 경우이를 사용할 필요는 없지만 성공적인 코드에 반응하는 코드가 성공적인 코드와 동일한 예외를 발생시킬 수 있으며 두 번째 가능한 예외를 보내거나 성공하면 즉시 돌아갑니다 (제 경우 스레드를 죽일 것입니다).


1

else블록은 종종 모든 발생 기능을 보완하기 위해 존재할 수 except블록을.

try:
    test_consistency(valuable_data)
except Except1:
    inconsistency_type = 1
except Except2:
    inconsistency_type = 2
except:
    # Something else is wrong
    raise
else:
    inconsistency_type = 0

"""
Process each individual inconsistency down here instead of
inside the except blocks. Use 0 to mean no inconsistency.
"""

이 경우 inconsistency_type블록을 제외하고 각 예외 블록에 설정되어 오류가없는 경우의 동작이 보완됩니다 else.

물론, 나는 이것을 언젠가 자신의 코드에서 나타날 수있는 패턴으로 설명하고 있습니다. 이 특정 경우, 블록 inconsistency_type전에 try어쨌든 0으로 설정 하면 됩니다.


1

이 패턴을 사용하고 싶은 또 다른 장소는 다음과 같습니다.

 while data in items:
     try
        data = json.loads(data)
     except ValueError as e:
        log error
     else:
        # work on the `data`

1
continue대신 "일찍 터뜨리기"패턴을 대신 사용할 수 있습니다 . 이렇게하면 "else"절과 들여 쓰기를 삭제하여 코드를보다 쉽게 ​​읽을 수 있습니다.
malthe

1

내가 생각할 수있는 사용 시나리오 중 하나는 예기치 않은 예외이며 다시 시도하면 우회 할 수 있습니다. 예를 들어 try 블록의 연산에 난수가 포함 된 경우 :

while True:
    try:
        r = random.random()
        some_operation_that_fails_for_specific_r(r)
    except Exception:
        continue
    else:
        break

그러나 예외를 예측할 수 있으면 항상 예외보다 먼저 유효성 검사를 선택해야합니다. 그러나 모든 것을 예측할 수있는 것은 아니기 때문에이 코드 패턴이 적합합니다.


1
break내부를 try끝에 배치하면 더 깨끗한 IMO가 가능하며을 필요로하지 않습니다 else. 또한 continue실제로 필요하지는 않습니다 pass.
Dirbaio 2016 년

1

else잘못된 구성 파일을 처리하는 데 유용한 것으로 나타났습니다 .

try:
    value, unit = cfg['lock'].split()
except ValueError:
    msg = 'lock monitoring config must consist of two words separated by white space'
    self.log('warn', msg)
else:
     # get on with lock monitoring if config is ok

lock구성을 읽으면 예외가 잠금 모니터링을 비활성화하고 ValueErrors는 유용한 경고 메시지를 기록합니다.


1

프로그래밍 논리에 사전에 주어진 키가있는 항목이 있는지 여부에 의존한다고 가정하십시오. construct dict.get(key)사용 결과를 테스트 if... else...하거나 다음을 수행 할 수 있습니다.

try:
    val = dic[key]
except KeyError:
    do_some_stuff()
else:
    do_some_stuff_with_val(val)

-1

DB 세션을 처리 할 때 똑바로 보이는 또 다른 유스 케이스를 추가합니다.

    # getting a DB connection 
    conn = db.engine.connect()

    # and binding to a DB session
    session = db.get_session(bind=conn)

    try:
        # we build the query to DB
        q = session.query(MyTable).filter(MyTable.col1 == 'query_val')

        # i.e retrieve one row
        data_set = q.one_or_none()

        # return results
        return [{'col1': data_set.col1, 'col2': data_set.col2, ...}]

    except:
        # here we make sure to rollback the transaction, 
        # handy when we update stuff into DB
        session.rollback()
        raise

    else:
        # when no errors then we can commit DB changes
        session.commit()

    finally:
        # and finally we can close the session
        session.close()

-17

else:블록 혼란 (거의) 소용된다. 또한 forand while문의 일부입니다 .

실제로, 심지어- if문장에서도, else:찾기 어려운 버그를 생성하는 정말 끔찍한 방법으로 남용 될 수 있습니다.

이걸 고려하세요.

   if a < 10:
       # condition stated explicitly
   elif a > 10 and b < 10:
       # condition confusing but at least explicit
   else:
       # Exactly what is true here?
       # Can be hard to reason out what condition is true

에 대해 두 번 생각하십시오 else:. 일반적으로 문제입니다. if-statement를 제외하고는 피하고, else명시 적으로 만들기 위해 -conditioning을 고려하십시오 .


6
나는 이것에 동의하지 않습니다. "if-elif"블록에서 "else"는 "default"로 사용되며 C 언어의 "case"블록에서 사용됩니다. 다양한 조건에서 모든 사례를 다루었다고 생각 되더라도 항상 "기본"사례를 처리하는 것이 좋습니다.
Josip

1
@Josip : "기본값"으로 사용하면 혼동 될 수 있습니다. 문제는이 "기본"조건을 명확하게 정의하는 것입니다. 잘못 정의 된 기본 조건은 버기 동작의 근본 원인 일 수 있습니다. 그렇지 않으면 혼란의 원인이 될 수 있습니다. 그것은 시도하는 동안뿐만 아니라 시도하는 동안뿐만 아니라 모든 경우에 매우 신중하게 생각되어야합니다.
S.Lott

5
위의 코드는 완전히 추상적이고 의미있는 것을 수행하지 않으므로 혼란 스럽습니다.
julx

1
@ S.Lott "버그를 줄입니다"-제 요점은 이것이 거짓이라는 것입니다. 나는 우리가 의견에 진정한 차이가 있다고 생각합니다. 나쁜 프로그래머는 항상 버그가있는 프로그램을 작성하는 방법을 찾습니다. 항상. 좋은 프로그래머는 항상 좋은 습관을 찾고 거의 모든 언어로 좋은 코드를 작성할 수 있습니다. 유용한 구문을 제거하면 좋은 프로그래머에게는 힘이 덜 나가지 만 나쁜 것은 잘 풀지 못하는 무한한 방법을 발명 할 수 있기 때문에 특히 도움이되지 않습니다.
julx

5
고려 : if x > 0: return "yes"if x <= 0: return "no". 이제 사람이 와서 말할 조건 중 하나 x > 1를 바꾸지 만 다른 것을 바꾸는 것을 잊어 버립니다. 커밋되는 버그 수를 줄이는 방법은 무엇입니까? if else절은 때때로 여러 줄로 구분됩니다. DRY는 실제로는 아니지만 훨씬 더 좋은 습관입니다. (더블 포스트 죄송합니다).
julx
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.