如何控制cython cdef类的模块/名称?

时间:2014-07-03 05:46:37

标签: python c++ cython cpython

我使用cython将C ++库暴露给python,方法是将所有包装器对象和函数放在内部模块_pydynd中,然后通过不同的python模块公开它们。 我想控制出现在这些扩展类中的模块和类的名称,例如,看起来像dynd.nd.array,而不是_pydynd.w_array,它是包装类的内部名称。 cython是否有机制来做到这一点?

我希望找到类似于在编写定义时如何重命名C / C ++函数的东西,但我的搜索已经变得干脆了。生成的C ++代码应该是不同的tp_name行:

static PyTypeObject __pyx_type_7_pydynd_w_array = {
  PyVarObject_HEAD_INIT(0, 0)
  __Pyx_NAMESTR("_pydynd.w_array"), /*tp_name*/
  sizeof(struct __pyx_obj_7_pydynd_w_array), /*tp_basicsize*/

更新:

如果我尝试直接重命名对象,则会发生以下情况:

In [103]: nd.array.__name__
Out[103]: 'w_array'

In [104]: nd.array.__module__
Out[104]: 'dynd._pydynd'

In [105]: nd.array.__name__ = "array"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-105-73d9172a0216> in <module>()
----> 1 nd.array.__name__ = "array"

TypeError: can't set attributes of built-in/extension type 'dynd._pydynd.w_array'

In [106]: nd.array.__module__ = "dynd.nd"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-106-37f990658ede> in <module>()
----> 1 nd.array.__module__ = "dynd.nd"

TypeError: can't set attributes of built-in/extension type 'dynd._pydynd.w_array'

2 个答案:

答案 0 :(得分:2)

Cython-0.21似乎使用.pyx文件相对于__init__.py文件的位置来设置模块名称。

对于文件布局

jmap/__init__.py
jmap/client.pyx

cython编译器的输出包括

#define __Pyx_MODULE_NAME "jmap.client"

移动__init__.py的位置会更改此值。这些信息可能在Cython文档中,但我找不到它。

讨论

这对于正确行事至关重要正确的泡菜课程。具体而言,模块的名称概念应与导入方式对称。这看起来很明显,但很容易在cython中打破。

>>> from jmap.client import JMapError
>>> JMapError
<class 'jmap.client.JMapError'>

>>> import jmap
>>> jmap.JMapError
<class 'Client.client.JMapError'>

答案 1 :(得分:0)

我有一个部分解决你的问题的方法,你可以移动或者我们应该说更好地导入到__ init__.py文件中的专用命名空间。

让我们开始,你有一个lib,它有以下几点:

module.libname.A (A is a class for e.g. or anything else)
module.libname.B
...

现在我通过复制tings来创建自己的lib。在您的newmodule中找到的__ init__.py中,您可以执行以下操作:

__import__("module."+libname) # this import will import the library in the current context
globals().update(vars(module.libname))

# or use this
library = import_("PathToLibAndFilename", "module.")
globals().update(vars(library))

如果你从vars(库)迭代这些东西,你也可以重命名这些东西,但到目前为止我还没有尝试过。 update()需要一个字典,你可以传递一个你在布局中选择的字典。

您可以在控制台上使用它进行试验(我认为这是一个适合您的解决方案):

 import(libName)
 globals().update({"testMe":vars(libName)["A"]}) # A is your class name from the library
 # then you can do:
 testMe
 # in my case this outputs something like this: <class 'libName.A'>

PS:我使用boost :: python来公开我的类,但它只是cpython东西的包装。