Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

C 확장 모듈에서 Python 예외 발생시키는 방법

C 언어로 작성된 Python 확장 모듈에서도 일반적인 Python 코드와 마찬가지로 예외를 발생시킬 수 있습니다. C API 수준에서는 PyErr_SetString()이나 PyErr_Format() 같은 함수로 예외를 설정한 뒤 NULL을 반환하면 되며, 경우에 따라서는 C API 함수 자체가 내부적으로 예외를 설정하기도 합니다.

예외를 발생시키는 C 확장 예제

다음은 의도적으로 잘못된 형식 문자를 Py_BuildValue()에 전달해 예외를 유발하는 hello.c 예제입니다.

#include <Python.h>

static PyObject* helloworld(PyObject* self) {
   // 't'는 유효하지 않은 형식 문자이므로 예외가 발생함
   return Py_BuildValue("t");
}

static PyMethodDef myMethods[] = {
   { "helloworld", helloworld, METH_NOARGS, "예외 발생 테스트 함수" },
   { NULL, NULL, 0, NULL }
};

static struct PyModuleDef helloworldmodule = {
   PyModuleDef_HEAD_INIT,
   "helloworld",
   "C 확장 예외 테스트 모듈",
   -1,
   myMethods
};

PyMODINIT_FUNC PyInit_helloworld(void) {
   return PyModule_Create(&helloworldmodule);
}

Py_BuildValue()는 지원하지 않는 형식 문자를 만나면 스스로 예외를 설정하고 NULL을 반환합니다. 이렇게 설정된 예외는 이 함수를 호출한 Python 코드 쪽으로 그대로 전달됩니다.

setup.py 스크립트 작성

위 모듈을 빌드하고 설치하려면 다음과 같은 setup.py 스크립트가 필요합니다.

from distutils.core import setup, Extension
setup(name='helloworld', version='1.0', \
      ext_modules=[Extension('helloworld', ['hello.c'])])

확장 모듈 설치

다음 명령을 실행해 확장 모듈을 빌드하고 설치합니다.

$ python setup.py install

Python에서 예외 처리 확인

설치가 완료되면 Python 스크립트(test.py)에서 해당 확장 모듈을 임포트하고, try-except 블록으로 발생한 예외를 잡아낼 수 있습니다.

#test.py
import helloworld

try:
    print(helloworld.helloworld())
except Exception as e:
    print(str(e))

이 스크립트를 실행하면 다음과 같은 결과가 출력됩니다.

bad format char passed to Py_BuildValue

이처럼 C 확장 내부에서 설정된 예외 메시지가 Python의 except 블록에서 정상적으로 처리되는 것을 확인할 수 있습니다. 나아가 PyErr_NewException()을 사용하면 새로운 예외 타입을 직접 정의해 모듈 외부에 노출할 수도 있으므로, 더 세밀한 오류 처리가 필요한 경우 활용해 보시기 바랍니다.