Как определить метакласс Python с Boost.Python? - PullRequest
14 голосов
/ 29 января 2012

Python C API имеет объект PyObject *PyType_Type, что эквивалентно type в интерпретаторе. Если я хочу определить метакласс в C ++, как я могу установить type в качестве одной из его баз в Boost.Python? Кроме того, что еще нужно учитывать при определении метакласса Python в C ++?

Было бы идеально, если бы для этого было решение Boost.Python. Если нет, то решение, которое использует Python C API (или комбинацию Boost и C API), также хорошо. Поскольку другие мои классы открыты с помощью Boost, я бы предпочел оставить SWIG в качестве крайней меры.

Примечание: На самом деле это часть более крупной проблемы, которую я пытаюсь решить, о которой я спрашивал в Установка метакласса обернутого класса с Boost.Python , если Вы заинтересованы.

1 Ответ

4 голосов
/ 06 февраля 2012

Хорошо, это похоже на взлом, но, похоже, работает.

#include <boost/python.hpp>

class Meta
{
public:
    static boost::python::object
    newClass(boost::python::object cls, std::string name, boost::python::tuple bases, boost::python::dict attrs)
    {
        attrs["foo"] = "bar";
        boost::python::object types = boost::python::import("types");
        boost::python::object type = types.attr("TypeType");
        return type.attr("__new__")(type, name, bases, attrs);
    }
};

BOOST_PYTHON_MODULE(meta)
{
    boost::python::class_<Meta>("Meta")
    .def("__new__", &Meta::newClass)
    .staticmethod("__new__");
}

тогда в питоне

from meta import Meta

class Test(object):
    __metaclass__ = Meta

print Test, Test.foo
<class '__main__.Test'> bar

Я пробовал некоторые другие вещи, которые не использовали систему boost :: python :: object, но не могли получить ничего, что работало бы так со стороны python.

Хотя, строго говоря, это не метакласс, поскольку он не наследуется от типа, но он ведет себя как единица, потому что тип используется непосредственно в функции newClass при вызове new. Если это не проблема, то, возможно, было бы разумно изменить его с

return type.attr("__new__")(type, name, bases, attrs);

до

return type.attr("__new__")(cls.attr("__class__"), name, bases, attrs);

или что-то подобное, так что вместо типа используется Boost :: Python :: class.

...