簡體   English   中英

Py_InitModule復制名稱但不復制函數指針?

[英]Py_InitModule copies the name but not the function pointer?

當我使用Py_InitModule注冊回調時,並且以后如果在結構中更改函數指針以指向新函數時,將調用新函數。 但是,如果我更改名稱,則無法識別新名稱。

#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;
}

這給出以下輸出:

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

這似乎是非常不一致的行為。 當我為PyMethodDef methods使用堆棧變量時,我第一次遇到它,一旦變量超出范圍,該程序便崩潰了,而我仍然嘗試從python調用C ++回調。 因此,我測試了更改指針的確確實會更改所調用的函數,即使沒有通過另一個Py_InitModule調用將其重新注冊也是Py_InitModule 但是同時,更改名稱沒有此行為。

到目前為止,我很確定PyMethodDef必須存在,只要python代碼嘗試調用方法(即不能是堆棧/局部變量),但是僅使用函數指針本身。

這是故意的行為還是某種疏忽? 該文檔沒有提及我能找到的有關PyMethodDef生存期的任何內容。

您看到的不一致是由函數代碼(即函數本身的屬性)與從模塊調用模塊的名稱(即模塊的屬性)(其字典中的鍵)之間的差異引起的。 雖然函數的名稱也存儲在函數對象中,但它僅用於repr ,而不是函數的基本屬性。

這是非常故意的,因為如果函數存儲在容器中,它允許在不同的地方以不同的名稱使用相同的函數對象,甚至不使用名稱。 如果僅通過更改函數的屬性就可以對其“重命名”,這將是不可能的。

可以使用常規Python函數來證明這一相同的區別,如下所示:

>>> 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回調ml_meth更改Python可調用項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM