我在Linux中使用gcc 4.8.2和Python 2.7为我的自定义C ++库构建python绑定。 我的代码中有以下文件夹结构
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
来达到这个目的。基本上在子模块1中我有一个PyObject * exportCapsule()
函数,在子模块2中我有一个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);
}
文件setup_submodule1.py
用于构建第一个模块::
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
文件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.so
和submodule2.so
。 我可以导入它们,而我不理解的是,我的胶囊内容不是必需的。这两个模块共享静态变量Singleton<myClass>::_ptrInstance
,而不必使用胶囊导出和导入。我怀疑它与
*.so
中的符号有关。如果我拨打nm -g *.so
我可以看到相同的符号。我真的很惊讶两个独立编译的模块可以共享一个变量。这是正常的吗?
我收到了一个明确的答案:两个模块共享变量,因为命名空间对于所有模块都是通用的,而我期望不同的命名空间。
答案 0 :(得分:1)
C ++ static
成员变量的重点在于它们在所有类的实例之间共享。实际上,它们不属于任何实例,而是属于类本身。它们本质上是命名空间全局变量的一种形式。
“所有实例”表示整个程序中的所有实例 ,对于Python模块,整个程序是Python解释器(即不是单个模块)。
不要将静态成员变量与静态文件范围变量混淆。他们的语义完全不同 - 实际上几乎相反。文件范围变量通常具有外部链接,这意味着声明的名称引用该变量在整个程序源中出现的任何位置,但该源在文件之间分配。另一方面,static
文件范围变量具有静态链接,这意味着声明的名称仅在声明出现的编译单元内引用该变量。
外卖:static
成员变量是全局变量,而static
文件范围变量是本地变量。欢迎来到C ++。