1

충분한 오류 검사가 포함되지 않은 Python 용 C 확장 모듈을 만든 코드를 검토하고있었습니다. 대부분의 경우에 쉽지만 모듈 초기화 함수에 관해서는 확실하지 않았습니다. PyModule_Create이 실패 할 경우 다음 (선한)PyModule_Add * 함수가 실패하면 모듈 init에서 C 확장이 실패해야합니까?

m = PyModule_Create(&itertoolsmodule); 
if (m == NULL) 
    return NULL; 

for (i=0 ; typelist[i] != NULL ; i++) { 
    if (PyType_Ready(typelist[i]) < 0) 
     return NULL; 
    name = strchr(typelist[i]->tp_name, '.'); 
    assert (name != NULL); 
    Py_INCREF(typelist[i]); 
    PyModule_AddObject(m, name+1, (PyObject *)typelist[i]); 
} 

return m; 

그것은 확인 않습니다 그것을 확인 : 그냥 토론을 위해서

,의이 (가) (abriged) module-init function for itertools (예, CPython에 의해 제공되는 하나) 보자 PyType_Ready이 실패하면 (좋은) 그러나 그 경우에는 Py_DECREF(m) (이는 놀랍거나 혼란 스럽습니다)하지만 PyModule_AddObject이 실패하는지 완전히 확인하지 못합니다. it's documentation에 따르면이 이 실패 할 수 있습니다 :

이름으로 모듈에 객체를 추가합니다. 이것은 모듈의 초기화 함수에서 사용할 수있는 편리한 함수입니다. 이것은 value에 대한 참조를 훔칩니다. 오류가 발생하면 -1을 반환하고 성공하면 0을 반환합니다.

좋아, 어쩌면 유형을 추가 할 수없는 경우를 대비해 모듈 초기화를 깨뜨리는 것이 과도한 것처럼 보일 수도 있습니다. 그러나 모듈을 완전히 작성하는 것을 중단하고 싶지 않은 경우에도 typelist[i]에 대한 참조가 누출되어야합니다. 맞습니까?

내장 된 CPython C 모듈은 module-init 함수에서 철저한 오류 검사 및 처리를하지 않기 때문에 (일반적으로 C 확장에 해당 함수가 없기 때문에) 대개 매우 빠릅니다 이러한 종류의 문제와 누출 가능성이 엄격합니다. 그래서 내 질문은 기본적으로 : 오류 체크는 특히 PyModule_Add* 함수 (예 : PyModule_AddObject)와 관련하여 모듈 초기화 기능에서 중요합니까? 아니면 CPython이 여러 곳에서하는 것처럼 생략 될 수 있습니까?

+0

나는 이것이 너무 답할 만하다고 생각한다. 하지만 몇 가지 생각 ... 1) 예기치 않은 오류가 발생할 경우 참조 횟수를 계산하는 것이 중요하지 않습니다. 개체 하나를 잃어 버리면 한 번만 발생하며 어쨌든 프로그램이 중단 될 가능성이 큽니다. 2)'PyModule_AddObject'의 대부분의 실패 모드는 항상 발생합니다 (즉, 모듈을 전달하지 않음). 모듈이 작동한다는 것을 알게되면 확인하지 않는 것이 좋습니다. – DavidW

+0

@DavidW 생각에 근거가 없기 때문에 투표가 닫히지 않는다고 생각하면 자유롭게 투표하십시오. 그러나 당신의 생각은 의미가 있습니다. 유일하게 (예측할 수없는) 실패 원인은 아마도'MemoryError' (char-> unicode) 일 것이며 어쨌든 모듈 가져 오기에서이를 해결하는 것은 의미가 없을 것입니다. 답변으로 게시하는 것이 좋습니다 (최소한 폐쇄해야한다고 생각하지 않는 경우).) – MSeifert

답변

2

저는 파이썬의 C API를 사용할 때 엄격한 오류 검사를 선호합니다. 사람들은 종종 긴 다단계 함수를 작성하고, 오류를 확인하지 않으며, 불가사의하게 실패 할 때 혼란스럽게 행동합니다. 이 경우 (모듈 초기화) 약간의 에러 검사가 필요함을 정당화 할 수 있습니다 :

주된 이유는이 기능들이 C 코드의 오류로 인해 실제로 실패 할 것이고 반복적으로이 작업을 수행한다는 것입니다. 그들은 예상치 못한 사용자에게 예기치 않게 실패 할 것입니다. 때문에 예를 들어 PyModule_AddObject 촬영, 그것은 실패 할 수 있습니다

  • 전달 된 첫 번째 인수는 모듈 아니다 (! 당신의 실수를)
  • 가 전달 된 객체가 NULL입니다
  • (당신이 이전에 확인해야한다) 이 모듈은 (이런 방법을 모르겠어요,하지만 난 당신이 방금 만든 모듈에 우연히 일어나는 볼 수 없습니다) 실패 PyUnicode_FromString에 의해 대부분 발생 (
  • PyDict_SetItemString이 실패 __dict__이 없습니다).

의견에서 지적한대로 후자는 MemoryError (언제든지 발생할 수 있으며 예측할 수 없음)으로 인한 것일 수 있습니다. 그러나 MemoryError에서 ~ 10 개의 문자열을 할당 할 때 파이썬 인터프리터가 더 오랫동안 계속 진행할 것 같지 않습니다.

내 결론은 "모듈이 제대로 작동하는 것 같으면 문제를 점검하는 것이 필요하지 않지만 상황이 잘못되면 어디에서 찾을 수 있습니까?"라고 생각합니다. 내가 추가 할 수있는 한 가지 모듈을 반환 직전 오류에 대한 최종 검사입니다 :

if (PyErr_Occurred()) return NULL; 
/* or */ 
if (PyErr_Occurred()) { 
    /* print a warning? */ 
    PyErr_Clear(); 
    return m; 
} 

그 이유는 오류 표시기가 설정되어있는 경우 파이썬은 매우 이상한 행동 할 수 있지만 NULL를 반환하지 않는다는 것입니다 (이상한 시간에 제기 된 예외는 의미가 없습니다.) 따라서 빠른 최종 점검에는 약간의 가치가 있습니다. 모듈 초기화가 실패 할 때 관련하여


이 처리를 참조하십시오 : 그것은 분명히입니다 "최고"바로 그것을 할,하지만 난 당신이 그것을 건너 뛰는 정당화 할 수 있다고 생각합니다. 이것은 한 번 실행되는 코드이므로 반복해서 소량을 잃어 버리면서 많은 양의 메모리를 잃을 수는 없습니다. 오류가 발생하면 프로그램이 중단되어 모든 메모리가 복구됩니다. 중단하지 않더라도 누출 크기는 매우 작습니다 (~ 100 바이트, 현실적으로).