2015-03-13 65 views
1

我正在Linux中使用gcc 4.8.2和Python 2.7为我的自定义C++库构建python绑定。 我有以下文件夹结构我的代码Python C界面,不同模块共享静态变量?

module/ 
    __init__.py 
    submodule1.so # first part of lib 
    submodule2.so # second part of lib 
    submodule3.py # additional python tools 

内。在__init__.py

import submodule1, submodule2 submodule3 

我需要通过对应于submodule1和submodule2之间静态类成员变量C++指针。 为此,我一直在使用capsules。基本上在submodule1我有一个PyObject * exportCapsule()功能和submodule2我有一个importCapsule(PyObject *)

现在,我发现我并不需要使用这些功能,我想知道为什么。 我收到John Bollinger的解释(请参阅下面的回复),关于不同的Python模块为静态类成员变量共享相同名称空间的事实。

我包一个完整的设置备案如下:

文件singleton.hpp定义类的静态成员的单样行为::

#ifndef _SINGLETON_HPP 
#define _SINGLETON_HPP 

// Singleton.hpp 

// declaration of class 
// + many more things 

template<typename T> 
class Singleton 
{ 
private: 
    static T * _ptrInstance; 

public: 
    static void setInstance(T* p) 
    { 
    _ptrInstance = p; 
    } 

    static bool doesInstanceExist() 
    { 
    bool output = not(NULL == _ptrInstance); 
    return output; 
    } 

    static T* getInstance() 
    { 
    return _ptrInstance; 
    } 
}; 

// declaration of static class 
template<typename T> 
T * Singleton<T>::_ptrInstance(NULL); 

#endif  

文件submodule1.cpp定义了第一模块::

//submodule1.cpp 

#include <Python.h> 
#include "singleton.hpp" 

static PyObject*errorObject; 


PyObject * exportCapsule(PyObject *dummy, PyObject *args) 
{ 
    long * ptr = Singleton<long>::getInstance(); 

    const char * caps_name = "ptrInstance"; 
    return PyCapsule_New((void *)ptr, caps_name, NULL); 
} 

PyObject* setValue(PyObject* self, PyObject* args) 
{ 
    if(not(Singleton<long>::doesInstanceExist())) 
    { 

    // printf("Singleton ptr %p \n",Singleton<long>::getInstance()); 
    // printf("Singleton is null %d \n",NULL==Singleton<long>::getInstance()); 
    PyErr_SetString(errorObject, "Singleton does not exist"); 
    return NULL; 
    } 


    PyObject * input; 
    PyArg_ParseTuple(args, "O", &input); 

    if (!PyLong_Check(input)) 
    { 
    PyErr_SetString(errorObject, "Input should be a long integer"); 
    return NULL; 
    } 


    long * ptr = Singleton<long>::getInstance(); 
    *ptr = PyLong_AsLong(input); 

    Py_INCREF(Py_None); 
    return Py_None; 
} 



PyMethodDef fonctions[] = { 
    {"setValue", setValue, METH_VARARGS, "set singleton value from long "}, 
    {"exportCapsule", exportCapsule, METH_VARARGS, "export singleton"}, 
    {NULL, NULL, 0, NULL} 
}; 


PyMODINIT_FUNC initsubmodule1(void) 
{ 

    PyObject* m = Py_InitModule("submodule1", fonctions); 

    errorObject = PyErr_NewException("submodule1.Exception", NULL, NULL); 

    Py_INCREF(errorObject); 
    PyModule_AddObject(m, "Exception",errorObject); 


    long * ptr = new long(0); 
    Singleton<long>::setInstance(ptr); 
} 

文件submodule2.cpp定义第二个模块::

//submodule2.cpp 

#include <Python.h> 
#include "singleton.hpp" 

static PyObject*errorObject; 


// to be checked 
PyObject * importCapsule(PyObject *dummy, PyObject *args) 
{ 


    const char * caps_name = "ptrInstance"; 

    PyObject * caps; 
    PyArg_ParseTuple(args, "O", &caps); 

    // we should also check the name... laziness 
    if (not(PyCapsule_CheckExact(caps))) 
    { 
    PyErr_SetString(errorObject, "Input is not a capsule"); 
    return NULL; 
    } 


    long * ptr = (long *) PyCapsule_GetPointer(caps, caps_name); 

    // if we want to set the same pointer it is ok 
    if (Singleton<long>::doesInstanceExist()); 
    { 
    long * ptrPrevious = Singleton<long>::getInstance(); 



    if (not(ptr == ptrPrevious)) 
    { 
     PyErr_SetString(errorObject, "You've asked for setting the global ptr with a different value"); 
     return NULL; 
    } 
    else 
    { 
     PyErr_SetString(errorObject, "You've asked for setting the global ptr with same value"); 
     return NULL; 

    } 
    } 

    Singleton<long>::setInstance(ptr); 

    Py_INCREF(Py_None); 
    return Py_None; 

} 


PyObject* getValue(PyObject* self, PyObject* args) 
{ 
    if (not(Singleton<long>::doesInstanceExist())) 
    { 
    PyErr_SetString(errorObject, "Singleton does not exist"); 
    return NULL; 
    } 

    long val = *Singleton<long>::getInstance(); 

    return PyLong_FromLong(val); 
} 


PyMethodDef fonctions[] = { 
    {"getValue", getValue, METH_VARARGS, "get long from singleton value"}, 
    {"importCapsule", importCapsule, METH_VARARGS, "import singleton as capsule"}, 
    {NULL, NULL, 0, NULL} 
}; 


PyMODINIT_FUNC initsubmodule2(void) 
{ 

    PyObject* m = Py_InitModule("submodule2", fonctions); 

    errorObject = PyErr_NewException("submodule2.Exception", NULL, NULL); 

    Py_INCREF(errorObject); 
    PyModule_AddObject(m, "Exception", errorObject); 


} 

建设第一个模块::

from distutils.core import setup, Extension 

submodule1 = Extension('submodule1', sources = ['submodule1.cpp']) 

setup (name = 'PackageName', 
     version = '1.0', 
     description = 'This is a demo package', 
     ext_modules = [submodule1]) 

文件setup_submodule2.py建设第二个模块::

from distutils.core import setup, Extension 

submodule2 = Extension('submodule2', sources = ['submodule2.cpp']) 

setup (name = 'PackageName', 
     version = '1.0', 
     description = 'This is a demo package', 
     ext_modules = [submodule2]) 

文件test.py用于测试目的::

if __name__ == "__main__": 

    print '----------------------------------------------' 
    print 'import submodule2' 
    print 'submodule2.getValue()' 

    import submodule2 

    try: 
     submodule2.getValue() 
    except Exception, e: 
     print ' ## catched :', e 

    print '----------------------------------------------' 
    print 'import submodule1' 
    print 'submodule1.setValue(1L)' 

    import submodule1 
    submodule1.setValue(1L) 
    print 'submodule2.getValue() ->', submodule2.getValue() 

    print '----------------------------------------------' 
    print 'capsule = submodule1.exportCapsule()' 
    print 'submodule2.importCapsule(capsule)' 

    capsule = submodule1.exportCapsule() 

    try: 
     submodule2.importCapsule(capsule) 
    except Exception, e: 
     print ' ## catched :', e 

文件文件setup_submodule1.py cha的Makefile进不去一切::

submodule1: 
    python setup_submodule1.py build_ext --inplace 

submodule2: 
    python setup_submodule2.py build_ext --inplace 

test: 
    python test.py 

all: submodule1 submodule2 test 

而且make all输出::

python test.py 
---------------------------------------------- 
import submodule2 
submodule2.getValue() 
    ## catched : Singleton does not exist 
---------------------------------------------- 
import submodule1 
submodule1.setValue(1L) 
submodule2.getValue() -> 1 
---------------------------------------------- 
capsule = submodule1.exportCapsule() 
submodule2.importCapsule(capsule) 
    ## catched : You've asked for setting the global ptr with same value 

原来的问题是:

编译后,我有两个不同的模块submodule1.sosubmodule2.so。 我可以导入它们,而我不明白的是,我的胶囊是不需要的。这两个模块共享静态变量Singleton<myClass>::_ptrInstance,而不必使用胶囊导出和导入。

我怀疑它与*.so中的符号有关。如果我拨打nm -g *.so,我可以看到相同的符号。

我真的很惊讶,两个独立编译的模块可以共享一个变量。这是正常的吗?

我收到了一个明确的答案:这两个模块共享变量,因为名称空间对于所有模块都是通用的,而我期待着不同的名称空间。

+0

是'template T * Singleton :: _ ptrInstance(NULL);'实际上在一个头文件中?这不应该工作。 – QuestionC 2015-03-13 21:11:38

+0

继您的评论后,我使用完整设置更新了该问题。您可以找到重现我的实验所需的所有文件。 – MathiasOrtner 2015-03-15 17:36:06

回答

1

C++ static成员变量的重点在于它们在其类的所有实例之间共享。事实上,他们不属于任何实例,而是属于类本身。它们本质上是名称空间全局变量的一种形式。

“所有实例”表示整个程序中的所有实例,对于Python模块,整个程序是Python解释器(即不是单独的模块)。

不要混淆静态成员变量与静态文件范围变量,但是。它们的语义实际上是完全不同的 - 几乎相反。文件范围变量通常具有外部链接,这意味着声明的名称是指在整个程序源中出现的任何地方的变量,但是该源在文件中被分割。另一方面,static文件范围变量具有静态链接,这意味着声明的名称仅在声明出现的编译单元中引用该变量。

外卖:static成员变量是全局变量,而static文件变量是局部变量。欢迎来到C++。

+0

非常感谢您的快速回答。我意识到''static''成员的行为。但是,我相信不同的模块会有不同的命名空间.... – MathiasOrtner 2015-03-13 18:29:06