Я использую 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'
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'>
У меня есть частичное решение вашей проблемы, вы можете переместить или, скажем так, лучше импортировать вещи в выделенное пространство имен в вашем файле __ init__.py.
Давайте начнем, у вас есть библиотека, которая имеет следующие вещи:
module.libname.A (A is a class for e.g. or anything else)
module.libname.B
...
Теперь я создал свою собственную библиотеку, скопировав все. В вашем __ 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.