Как сохранить имя класса С++ без изменений с помощью Cython?

У меня есть класс С++ под названием Foo. Если я буду следовать руководству по Cython C++, мне нужно будет вызывать класс Python по-другому, Пифу например. Однако мне действительно нужно также вызвать класс Python Foo. Как это сделать эффективно?

Изменить: я пытаюсь подключить существующую библиотеку C++, которая ранее была связана с Boost Python. По разным причинам я хотел бы вместо этого протестировать Cython. Поскольку в Boost:Python классы Python вызывались с теми же именами, что и в C++, я хотел бы продолжить это соглашение об именах. Это не требование Python (CPython) вызывать классы по-разному, но кажется, что Cython навязывает это, по крайней мере, в учебнике.

Конечно, я могу использовать чистый модуль Python для определения класса Foo, который вызывает PyFoo, но это кажется скучным и неэффективным.


person ascobol    schedule 11.04.2012    source источник
comment
Почему бы вместо этого не сделать класс C++ CppFoo?   -  person Karl Knechtel    schedule 12.04.2012
comment
Потому что тогда мне также нужно будет вызвать класс Python CppFoo...   -  person ascobol    schedule 12.04.2012
comment
Что заставляет вас думать, что имя PyFoo особенное? Насколько я могу судить, единственным реальным требованием является то, чтобы имена были разными, и единственная причина этого в том, что вы собираетесь ссылаться на тип C++ в реализации типа Python.   -  person Karl Knechtel    schedule 12.04.2012
comment
Я отредактировал свой вопрос, чтобы лучше понять свои цели.   -  person ascobol    schedule 12.04.2012
comment
Почему бы не иметь модуль, который работает с Cython, чтобы все работало правильно, даже если вы недовольны именованием, а затем сделать другой модуль, который служит фасадом, который мало что делает, кроме чего-то вроде 'from _CppFoo import *; Фу = ПиФу'   -  person Arafangion    schedule 12.04.2012
comment
@Arafangion, это лучшее решение, которое я нашел до сих пор. Сначала я думал, что это замедлит вызовы модуля C++, но теперь я понимаю, что это может быть не так.   -  person ascobol    schedule 12.04.2012


Ответы (2)


Есть два способа справиться с этим.

  1. Объявить класс C++ с альтернативным именем; оригинальное имя должно быть указано в двойных кавычках:

    cdef extern from "defs.h" namespace "myns":
        cdef cppclass CMyClass "myns::MyClass":
            ...
    

    Затем вы можете использовать MyClass для своего класса Python и ссылаться на объявление C++ как CMyClass.

    Обратите внимание, что исходное имя должно явно включать пространство имен (если оно находится в пространстве имен). Аргументы шаблона Cython (если они есть) должны идти после объявления альтернативного имени.

  2. Объявите свои классы C++ в отдельном файле .pxd с именем, отличным от файла .pyx, а затем импортируйте их с помощью cimport.

    В cpp_defs.pxd:

    cdef extern from "defs.h" namespace "myns":
        cdef cppclass MyClass:
            ...
    

    В py_wrapper.pyx:

    cimport cpp_defs as cpp
    
    cdef class MyClass:
        cpp.MyClass *_obj
    
person Nikita Nemkin    schedule 12.04.2012
comment
Для меня второй вариант жалуется на переопределение MyClass в py_wrapper.pyx, хотя кажется, что cpp.MyClass действительно следует рассматривать как отдельную вещь. Первый вариант отлично работает для меня, хотя namespace "myns" должен быть в предыдущей строке, так как cdef extern from "defs.h" namespace "myns": или cython жалуется на синтаксическую ошибку. [Использование Cython версии 0.20.1.] - person Mike; 06.03.2014
comment
Есть ли способ сделать это для функций? - person Alex Flint; 19.06.2014
comment
В чем проблема с функциями? Текстовое переопределение (в двойных кавычках) работает для всех объектов cdef: классов, функций, структур, определений типов и т. д. Перемещение объявлений в отдельный .pxd (более естественное решение для пространства имен) также работает для всего. - person Nikita Nemkin; 19.06.2014
comment
@Mike Для второго варианта файлы pyd и pyx должны иметь разные имена. - person aberaud; 05.08.2015

Вот полный пример, демонстрирующий подход Никиты:

cdef extern from "floorplan_geometry.h" namespace "flyby::localize":
    cdef cppclass CFloorplan "flyby::localize::Floorplan":
        int xmin()

cdef class Floorplan:
    cdef CFloorplan* obj_
    def __cinit__(self):
        self.obj_ = new CFloorplan()
    def __dealloc__(self):
        del self.obj_
    def xmin(self):
        return self.obj_.xmin()
person Alex Flint    schedule 18.06.2014