2016-08-28 7 views
1

Py_InitModule을 사용하여 콜백을 등록 할 때 나중에 구조의 함수 포인터를 새 함수를 가리 키도록 변경하면 새 함수가 호출됩니다. 그러나 이름을 변경하면 새 이름이 인식되지 않습니다.Py_InitModule은 함수 포인터가 아닌 이름을 복사합니까?

foo1 
foo2 
foo2 
Traceback (most recent call last): 
    File "", line 1, in 
AttributeError: 'module' object has no attribute 'foo2'

이것은 매우 모순 된 것 같다

#include <Python.h> 

PyObject* foo1(PyObject *self, PyObject *args) 
{ 
    printf("foo1\n"); 
    Py_RETURN_NONE; 
} 

PyObject* foo2(PyObject *self, PyObject *args) 
{ 
    printf("foo2\n"); 
    Py_RETURN_NONE; 
} 

int main() 
{ 
    PyMethodDef methods[] = { 
     { "foo", foo1, METH_VARARGS, "foo" }, 
     { 0, 0, 0, 0 } 
    }; 

    Py_Initialize(); 
    Py_InitModule("foo", methods); 
    PyRun_SimpleString("import foo\n"); 
    PyRun_SimpleString("foo.foo()\n"); 
    methods[0].ml_meth = foo2; 
    PyRun_SimpleString("foo.foo()\n"); 
    methods[0].ml_name = "foo2"; 
    PyRun_SimpleString("foo.foo()\n"); 
    PyRun_SimpleString("foo.foo2()\n"); 
    return 0; 
} 

다음과 같은 출력을 제공합니다. 변수가 범위를 벗어나고 여전히 파이썬에서 C++ 콜백을 호출하려고 시도한 후에 프로그램을 크래시 한 PyMethodDef methods에 스택 변수를 사용했을 때 처음 만났습니다. 그래서 포인터를 변경하면 실제로 다른 Py_InitModule 호출과 함께 다시 등록하지 않은 함수를 호출 변경합니다. 그러나 동시에 이름을 변경해도 이러한 동작이 발생하지 않습니다.

지금까지 나는 PyMethodDef이 파이썬 코드가 메소드 (즉, 스택/로컬 변수가 될 수 없음)를 호출하려고하지만 함수 포인터 자체 만 사용되는 한 계속 살아야한다고 확신합니다.

의도적 인 행동입니까, 아니면 일부 감독입니까? 이 문서에는 찾을 수있는 PyMethodDef 수명에 대한 언급이 없습니다.

+1

예상됩니다. 'PyInit_Module'이 아무것도 초기화하지 않았다고 생각 했습니까? 해석기에게 어떤 속성/메소드가 나중에 검사하지 않도록 정의되었는지 알려줍니다. 함수의 이름을 동적으로 바꾸려면 1) 인터프리터에서 모듈 객체를 가져와야합니다. 2) PyObject_SetAttr (또는 비슷한 이름으로 정확한 이름을 기억하지 못합니다)을 사용하여 모듈 객체의 속성을 설정합니다. – Bakuriu

+0

@Bakuriu 감사합니다. 그러나 왜'ml_math' 필드도 복사되지 않았습니까? 즉, 나중에 함수를 변경하면 호출 할 함수를 핫 스왑하는 이유는 무엇입니까? – sashoalm

답변

2

표시되는 불일치는 함수 자체의 속성 인 모듈의 속성 인 모듈의 속성 인 모듈의 속성 인 모듈의 속성 인 dict). 함수 이름도 함수 객체에 저장되지만 repr에만 사용되며 함수의 기본 속성은 아닙니다.

기능이 컨테이너에 저장되어있는 경우 다른 이름 또는 이름이없는 다른 위치에서 동일한 함수 개체를 사용할 수 있으므로 이는 매우 의도적 인 작업입니다. 함수의 속성을 변경하는 것만으로 "이름을 바꿀"수있는 경우에는 불가능합니다.

하나는 다음과 같이 일반 파이썬 함수를 사용하여이 같은 차이를 보여줄 수 : 코멘트에있는 당신의 질문에 대해서는

>>> def add(a, b): return a + b 
... 
>>> def sub(a, b): return a - b 
... 
>>> add 
<function add at 0x7f9383127938> # the function has a name 
>>> add.__name__ = 'foo' 
>>> add       # the name is changed, but... 
<function foo at 0x7f9383127938> 
>>> foo       # the change doesn't affect the module 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'foo' is not defined 
>>> add.__code__ = sub.__code__ # we can change the code, though 
>>> add(2, 2) 
0 

: 메소드 필드는 복사되지 않습니다 Py_InitModule 및 관련 함수를 호출 할 수 있도록 설계되어 있기 때문에 정적으로 할당 된 구조체는 공간을 낭비하는 복사본을 만듭니다. 복사하지 않으면 ml_meth에서 실제 C 콜백을 변경하면 파이썬 호출 가능이 변경되는 이유가 설명됩니다.