Подтвердить что ты не робот

Как определить метакласс Python с помощью Boost.Python?

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

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

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

4b9b3361

Ответ 1

Хорошо, это похоже на хак, но, похоже, это работает.

#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__");
}

а затем в python

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.