Как правильно определить атрибуты в расширении PyCXX?

Интересно, как правильно определить атрибуты в расширении Python, созданном с помощью PyCxx. В настоящее время я создал подкласс Py::PythonClass как в официальном примере. я добавил behaviors().supportGetattro(); в функции инициализации и создали простое переопределение

Py::Object getattro( const Py::String &name_ )
{
    std::string name( name_.as_std_string( "utf-8" ) );

    if( name == "name" )
    {
        return m_name;
    }
    else
    {
        return genericGetAttro( name_ );
    }
}

Все идет нормально. В Python я получаю правильное значение с obj.name, но единственное, что меня бесит, это то, что при звонке dir(obj) name атрибут не попадает в список. Как я могу это изменить?

2 ответа

Решение

Барри Скотт, разработчик PyCXX, любезно предоставил простое решение. Хитрость в том, что питон запрашивает значение __members__ в getattr( const char *_name ) при звонке dir(), В этом случае можно вернуть Py::List объект, содержащий имена атрибутов в виде строк.

Для Python 3 используется__dict__член вgetattr( const char *_name )(помимо прочего). Ожидается, что это будетPy:Dictсвязывание имен атрибутов с их значениями.

The dirфункция сохраняет только имя атрибута для возвращаемого значения.

Вот кодdir()чтобы получить ответ.

      static PyObject *
object_dir(PyObject *self, PyObject *args)
{
    PyObject *result = NULL;
    PyObject *dict = NULL;
    PyObject *itsclass = NULL;

    /* Get __dict__ (which may or may not be a real dict...) */
    dict = _PyObject_GetAttrId(self, &PyId___dict__);
    if (dict == NULL) {
        PyErr_Clear();
        dict = PyDict_New();
    }
    else if (!PyDict_Check(dict)) {
        Py_DECREF(dict);
        dict = PyDict_New();
    }
    else {
        /* Copy __dict__ to avoid mutating it. */
        PyObject *temp = PyDict_Copy(dict);
        Py_DECREF(dict);
        dict = temp;
    }

    if (dict == NULL)
        goto error;

    /* Merge in attrs reachable from its class. */
    itsclass = _PyObject_GetAttrId(self, &PyId___class__);
    if (itsclass == NULL)
        /* XXX(tomer): Perhaps fall back to obj->ob_type if no
                       __class__ exists? */
        PyErr_Clear();
    else if (merge_class_dict(dict, itsclass) != 0)
        goto error;

    result = PyDict_Keys(dict);
    /* fall through */
error:
    Py_XDECREF(itsclass);
    Py_XDECREF(dict);
    return result;
}
Другие вопросы по тегам