파이썬 코드를 실행할 때 예상되는 예외를 (코딩 할 때) 아는 방법이 있습니까? 나는 어떤 예외 유형이 던져 질 수 있는지 모르기 때문에 90 %의 시간 동안 기본 Exception 클래스를 잡게됩니다. 문서가 업데이트되거나 정확하지 않은 경우). 이것을 확인하는 도구가 있습니까? (파이썬 코드와 라이브러리를 읽는 것과 같이)?
except Exception
Python 2.6 이상에서 문자열 예외를 포착하는 데 잘 작동합니다.
파이썬 코드를 실행할 때 예상되는 예외를 (코딩 할 때) 아는 방법이 있습니까? 나는 어떤 예외 유형이 던져 질 수 있는지 모르기 때문에 90 %의 시간 동안 기본 Exception 클래스를 잡게됩니다. 문서가 업데이트되거나 정확하지 않은 경우). 이것을 확인하는 도구가 있습니까? (파이썬 코드와 라이브러리를 읽는 것과 같이)?
except Exception
Python 2.6 이상에서 문자열 예외를 포착하는 데 잘 작동합니다.
답변:
정적 타이핑 규칙이 없기 때문에 해결책이 정확하지 않을 수 있다고 생각합니다.
예외를 확인하는 도구에 대해서는 잘 모르지만, 자신의 필요에 맞는 도구를 찾을 수 있습니다 (정적 분석을 약간 사용할 수있는 좋은 기회).
첫 번째 시도로 AST를 빌드하고 모든 Raise
노드를 찾은 다음 예외를 발생시키는 일반적인 패턴을 파악 하는 함수를 작성할 수 있습니다 (예 : 생성자를 직접 호출).
하자 x
다음과 같은 프로그램이 될 :
x = '''\
if f(x):
raise IOError(errno.ENOENT, 'not found')
else:
e = g(x)
raise e
'''
compiler
패키지를 사용하여 AST를 빌드합니다 .
tree = compiler.parse(x)
그런 다음 Raise
방문자 클래스를 정의하십시오 .
class RaiseVisitor(object):
def __init__(self):
self.nodes = []
def visitRaise(self, n):
self.nodes.append(n)
그리고 AST 수집 Raise
노드를 살펴 봅니다 .
v = RaiseVisitor()
compiler.walk(tree, v)
>>> print v.nodes
[
Raise(
CallFunc(
Name('IOError'),
[Getattr(Name('errno'), 'ENOENT'), Const('not found')],
None, None),
None, None),
Raise(Name('e'), None, None),
]
컴파일러 기호 테이블을 사용하여 기호를 해결하고 데이터 종속성을 분석하는 등 계속할 수 있습니다. 또는 CallFunc(Name('IOError'), ...)
"확실히 제기하는 것을 의미해야 합니다 "라고 추론 할 수 있습니다 IOError
. 이는 빠른 실제 결과를 위해 매우 좋습니다. :)
v.nodes
위 의 값이 주어지면 실제로 어떤 것이 Name('IOError')
또는 무엇인지 말할 수 없습니다 Name('e')
. 소위 자유 변수이기 때문에 그 값 IOError
과 e
가리킬 수 있는 값을 알 수 없습니다 . 바인딩 컨텍스트가 알려졌더라도 (여기서는 기호 테이블이 작동 함) 정확한 값을 추론하기 위해 일종의 데이터 종속성 분석을 수행해야합니다 (파이썬에서는 어렵습니다).
['IOError(errno.ENOENT, "not found")', 'e']
있으므로 사용자에게 표시 되는 목록은 괜찮습니다. 하지만 당신은 변수의 값의 실제 클래스 (죄송합니다 다시 게시 용) 문자열 :)으로 표시 할 수없는 추론
exc_class = raw_input(); exec "raise " + exc_class
. 요점은 이러한 종류의 정적 분석이 Python과 같은 동적 언어에서는 실제로 가능하지 않다는 것입니다.
find /path/to/library -name '*.py' | grep 'raise '
비슷한 결과를 :) 얻을
처리 할 예외 만 포착해야합니다.
구체적인 유형별로 모든 예외를 포착하는 것은 말도 안됩니다. 당신은 당신이 특정 예외를 잡을해야 할 수 및 합니다 처리합니다. 다른 예외의 경우, "기본 예외"를 포착하고이를 기록 ( str()
함수 사용 )하고 프로그램을 종료하는 (또는 충돌 상황에 적합한 다른 작업을 수행 하는) 일반적인 catch를 작성할 수 있습니다 .
실제로 모든 예외를 처리 하고 치명적인 예외가 없다고 확신하는 경우 (예 : 샌드 박스 환경에서 코드를 실행하는 경우) 일반적인 BaseException을 포착하는 방법이 목표에 적합합니다.
사용중인 라이브러리에 대한 참조 가 아닌 언어 예외 참조 에도 관심이있을 수 있습니다 .
라이브러리 참조가 정말 열악하고 시스템 참조를 잡을 때 자체 예외를 다시 발생시키지 않는 경우 유일한 유용한 접근 방식은 테스트를 실행 하는 것입니다 (문서화되지 않은 경우 변경 될 수 있으므로 테스트 스위트에 추가 할 수 있습니다!). . 코드에 중요한 파일을 삭제하고 어떤 예외가 발생하는지 확인하십시오. 너무 많은 데이터를 제공하고 어떤 오류가 발생하는지 확인하십시오.
어쨌든 테스트를 실행 해야 할 것입니다 . "필요한 파일을 찾을 수 없습니다!"라는 오류 메시지가 표시 될 수 있습니다. 잡을 때 IndexError
? 테스트 만이 알 수 있습니다.
이 문제를 해결하는 올바른 도구는 단위 테스트입니다. unittest에서 발생하지 않는 실제 코드에서 예외가 발생하는 경우 더 많은 unittest가 필요합니다.
이걸 고려하세요
def f(duck):
try:
duck.quack()
except ??? could be anything
오리는 모든 객체가 될 수 있습니다.
분명히 AttributeError
if duck에 돌팔이가 없을 수 있고 TypeError
if duck에는 돌팔이가 있지만 호출 할 수 없습니다. 당신은 무슨 생각이 없다 duck.quack()
하지만 인상, 어쩌면 수 DuckError
또는 무언가를
이제 다음과 같은 코드가 있다고 가정합니다.
arr[i] = get_something_from_database()
a IndexError
가 발생하면 arr [i]에서 왔는지 아니면 데이터베이스 함수 내부에서 왔는지 알 수 없습니다. 일반적으로 예외가 발생한 위치는 그다지 중요하지 않습니다. 오히려 무언가 잘못되었고 원하는 일이 발생하지 않았습니다.
편리한 기술은 다음과 같이 예외를 포착하고 다시 발생시키는 것입니다.
except Exception as e
#inspect e, decide what to do
raise
지금까지 아무도 설명하지 않았고, 100 % 정확한 예외 목록을 가질 수없는 이유를 설명하지 않았으므로 이에 대해 언급 할 가치가 있다고 생각했습니다. 그 이유 중 하나는 일류 기능입니다. 다음과 같은 기능이 있다고 가정 해 보겠습니다.
def apl(f,arg):
return f(arg)
이제 apl
발생하는 모든 예외를 발생시킬 수 있습니다 f
. 핵심 라이브러리에는 이와 같은 기능이 많지 않지만 사용자 정의 필터, 맵, 축소 등과 함께 목록 이해를 사용하는 모든 기능이 영향을받습니다.
문서와 소스 분석기는 여기서 유일하게 "심각한"정보 소스입니다. 그들이 할 수없는 것을 명심하십시오.
나는 소켓을 사용할 때 이것을 만났고, 내가 실행할 모든 오류 조건을 찾고 싶었습니다 (그래서 오류를 만들고 어떤 소켓이 간결한 목록을 원했는지 알아내는 대신). 궁극적으로 "raise"에 대해 "/usr/lib64/python2.4/test/test_socket.py"를 grep'ing했습니다.
$ grep raise test_socket.py
Any exceptions raised by the clients during their tests
raise TypeError, "test_func must be a callable function"
raise NotImplementedError, "clientSetUp must be implemented."
def raise_error(*args, **kwargs):
raise socket.error
def raise_herror(*args, **kwargs):
raise socket.herror
def raise_gaierror(*args, **kwargs):
raise socket.gaierror
self.failUnlessRaises(socket.error, raise_error,
self.failUnlessRaises(socket.error, raise_herror,
self.failUnlessRaises(socket.error, raise_gaierror,
raise socket.error
# Check that setting it to an invalid value raises ValueError
# Check that setting it to an invalid type raises TypeError
def raise_timeout(*args, **kwargs):
self.failUnlessRaises(socket.timeout, raise_timeout,
def raise_timeout(*args, **kwargs):
self.failUnlessRaises(socket.timeout, raise_timeout,
꽤 간결한 오류 목록입니다. 물론 이것은 사례별로 만 작동하며 테스트가 정확한지에 따라 다릅니다 (보통 그렇습니다). 그렇지 않으면 거의 모든 예외를 잡아 내고 로그하고 분석하고 처리 방법을 파악해야합니다 (단위 테스트에서는 어렵지 않습니다).
내가 유익하다고 생각한 두 가지 방법이 있습니다. 첫 번째는 iPython에서 코드를 실행하여 예외 유형을 표시합니다.
n = 2
str = 'me '
str + 2
TypeError: unsupported operand type(s) for +: 'int' and 'str'
두 번째 방법으로 우리는 너무 많이 잡는 것에 안주하고 시간이 지남에 따라 개선합니다. try
코드에 표현식을 포함하고 except Exception as err
. 어떤 예외가 발생했는지 알기 위해 충분한 데이터를 인쇄하십시오. 예외가 발생하면 더 정확한 except
절 을 추가하여 코드를 개선하십시오 . 모든 관련 예외를 포착했다고 생각되면 모든 예외를 제거하십시오. 어쨌든 프로그래밍 오류를 삼키기 때문에 좋은 일입니다.
try:
so something
except Exception as err:
print "Some message"
print err.__class__
print err
exit(1)
일반적으로 몇 줄의 코드에서만 예외를 포착하면됩니다. 전체 main
기능을 try except
절 에 넣고 싶지 않을 것 입니다. 몇 줄마다 어떤 종류의 예외가 발생할 수 있는지 항상 (또는 쉽게 확인할 수 있어야합니다).
문서에는 기본 제공 예외 의 전체 목록이 있습니다. 예상하지 못한 예외를 제외하려고하지 마십시오. 호출 코드에서 처리 / 예상 될 수 있습니다.
편집 : 던질 수있는 것은 분명히 당신이하는 일에 달려 있습니다! 시퀀스의 임의 요소에 액세스 : IndexError
, dict의 임의 요소 : KeyError
등
IDLE에서 몇 줄을 실행하고 예외를 발생 시키십시오. 그러나 unittest는 당연히 더 나은 해결책이 될 것입니다.
raise
뿐 아니라 문자열도 사용할 수 있습니다BaseException
. 따라서 제어 할 수없는 라이브러리 코드를 호출하는 경우except Exception
문자열 예외를 포착하지 않기 때문에 충분하지 않습니다. 다른 사람들이 지적했듯이 여기에서 잘못된 나무를 짖고 있습니다.