2015-03-13 70 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