Как правильно определить атрибуты в расширении 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;
}