Python : 메서드 호출에서 발생할 수있는 예외를 어떻게 알 수 있습니까?
파이썬 코드를 실행할 때 어떤 예외가 예상되는지 (코딩 타임에) 아는 방법이 있습니까? 어떤 예외 유형이 던져 질 수 있는지 모르기 때문에 90 %의 시간 동안 기본 Exception 클래스를 잡게됩니다 (그리고 문서를 읽도록 말하지 마십시오. 예외는 깊은 곳에서 여러 번 전파 될 수 있습니다. 문서가 업데이트되지 않거나 정확하지 않은 경우). 이것을 확인하는 도구가 있습니까? (파이썬 코드와 라이브러리를 읽는 것과 같이)?
정적 타이핑 규칙이 없기 때문에 해결책이 정확하지 않을 수 있다고 생각합니다.
예외를 확인하는 일부 도구는 알지 못하지만 필요에 맞는 도구를 찾을 수 있습니다 (정적 분석을 약간 사용할 수있는 좋은 기회).
첫 번째 시도로 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. 이는 빠른 실제 결과를 위해 매우 좋습니다. :)
처리 할 예외 만 포착해야합니다.
구체적인 유형별로 모든 예외를 포착하는 것은 말도 안됩니다. 당신은 당신이 특정 예외를 잡을해야 할 수 및 합니다 처리합니다. 다른 예외의 경우, "기본 예외"를 포착하고이를 기록 ( str()함수 사용 )하고 프로그램을 종료하는 (또는 충돌 상황에 적합한 다른 작업을 수행 하는) 일반적인 catch를 작성할 수 있습니다 .
실제로 모든 예외를 처리 하고 치명적인 예외가 없다고 확신하는 경우 (예 : 샌드 박스 환경에서 코드를 실행하는 경우) 일반적인 BaseException을 포착하는 방법이 목표에 적합합니다.
사용중인 라이브러리에 대한 참조 가 아닌 언어 예외 참조 에도 관심이있을 수 있습니다 .
라이브러리 참조가 정말 열악하고 시스템 참조를 잡을 때 자체 예외를 다시 발생시키지 않는 경우 유일한 유용한 접근 방식은 테스트를 실행 하는 것입니다 (문서화되지 않은 항목이 있으면 변경 될 수 있으므로 테스트 스위트에 추가 할 수 있습니다!). . 코드에 중요한 파일을 삭제하고 어떤 예외가 발생하는지 확인하십시오. 너무 많은 데이터를 제공하고 어떤 오류가 발생하는지 확인하십시오.
어쨌든 테스트를 실행해야 할 것입니다. 소스 코드로 예외를 얻는 방법이 존재 하더라도 이러한 .NET Framework를 어떻게 처리해야하는지 알 수 없기 때문입니다 . "필요한 파일을 찾을 수 없습니다!"라는 오류 메시지가 표시 될 수 있습니다. 잡을 때 IndexError? 테스트 만이 알 수 있습니다.
이 문제를 해결하는 올바른 도구는 단위 테스트입니다. unittest에서 발생하지 않는 실제 코드에서 예외가 발생하면 더 많은 unittest가 필요합니다.
이걸 고려하세요
def f(duck):
try:
duck.quack()
except ??? could be anything
오리는 모든 객체가 될 수 있습니다.
분명히 AttributeErrorif duck에 돌팔이가 없을 수 있고 TypeErrorif 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
Noone explained so far, why you can't have a full, 100% correct list of exceptions, so I thought it's worth commenting on. One of the reasons is a first-class function. Let's say that you have a function like this:
def apl(f,arg):
return f(arg)
Now apl can raise any exception that f raises. While there are not many functions like that in the core library, anything that uses list comprehension with custom filters, map, reduce, etc. are affected.
The documentation and the source analysers are the only "serious" sources of information here. Just keep in mind what they cannot do.
I ran into this when using socket, I wanted to find out all the error conditions I would run in to (so rather than trying to create errors and figure out what socket does I just wanted a concise list). Ultimately I ended up grep'ing "/usr/lib64/python2.4/test/test_socket.py" for "raise":
$ 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,
Which is a pretty concise list of errors. Now of course this only works on a case by case basis and depends on the tests being accurate (which they usually are). Otherwise you need to pretty much catch all exceptions, log them and dissect them and figure out how to handle them (which with unit testing wouldn't be to difficult).
normally, you'd need to catch exception only around a few lines of code. You wouldn't want to put your whole main function into the try except clause. for every few line you always should now (or be able easily to check) what kind of exception might be raised.
docs have an exhaustive list of built-in exceptions. don't try to except those exception that you're not expecting, they might be handled/expected in the calling code.
edit: what might be thrown depends on obviously on what you're doing! accessing random element of a sequence: IndexError, random element of a dict: KeyError, etc.
Just try to run those few lines in IDLE and cause an exception. But unittest would be a better solution, naturally.
There are two ways that I found informative. The first one, run the instructions in iPython, which will display the exception type.
n = 2
str = 'me '
str + 2
TypeError: unsupported operand type(s) for +: 'int' and 'str'
In the second way we settle for catching too much and improving on it. Include a try expression in your code and catch except Exception as err. Print sufficient data to know what exception was thrown. As exceptions are thrown improve your code by adding a more precise except clause. When you feel that you have cached all relevant exceptions remove the all inclusive one. A good thing to do anyway because it swallows programming errors.
try:
so something
except Exception as err:
print "Some message"
print err.__class__
print err
exit(1)
'Programing' 카테고리의 다른 글
| NodeJS에서 CoffeeScript의 예? (0) | 2020.10.20 |
|---|---|
| Angular 2와 함께 D3.js 사용 (0) | 2020.10.20 |
| HTML5의 Keygen 태그 (0) | 2020.10.20 |
| HashPartitioner는 어떻게 작동합니까? (0) | 2020.10.19 |
| deltree에 무슨 일이 일어 났고 그 대체물은 무엇입니까? (0) | 2020.10.19 |