Как скопировать расширенный список питонов или его ссылку с помощью оператора «=»

0

взять этот код

#include<boost/python>
namespace bp = boost::python;

bp::list py_points; //initial list
other_class* C; // this class have a bp::list attribute called py_list

// ... some code ....

// in this part C.py_list.ptr() is 0x0

other_class->py_list = py_list; // problem here!!

проблема заключается в том, что оператор "="

в отладчике в файле object_core.hpp, это файл основного файла python

inline api::object_base& api::object_base::operator=(api::object_base const& rhs)
{
    Py_INCREF(rhs.m_ptr);
    Py_DECREF(this->m_ptr); // in this line the program fail
    this->m_ptr = rhs.m_ptr;
    return *this;
}

каков правильный способ использования оператора "="

отредактированный

проблема заключается в стеке, если указатель other_class-> py_list имеет значение null (или None, потому что конструктор класса не вызывается), программа не может вызывать función Py_DECREF (не существует ссылок до указателя NULL)

проблема заключается в исправлении вызова конструктора

other_class* C = new othe_class(); // fixed!!
Теги:
boost-python
python-extensions

1 ответ

2
Лучший ответ

Проблема заключается не в операторе присваивания, проблема в том, что внутренний указатель py_list PyObject является nullptr. В большинстве случаев указатель не должен быть нулевым. С точки зрения Python он должен по крайней мере управлять ссылкой на объект Python None, как это сделано по умолчанию построенным boost::python::object. Конструктор по умолчанию для boost::python::list создает новый пустой список. Следовательно, источник проблемы, вероятно, находится в конструкторе other_class или блоке "некоторый код".


Чтобы уточнить вопрос, поставленный в заголовке, создание справочного или копирующего списка в Boost.Python такое же, как в Python:

  • Оператор присваивания создаст ссылку на список.

    >>> a = ['spam']
    >>> b = a
    >>> b
    ['spam']
    >>> a is b
    True
    
  • Можно нарезать список, чтобы создать мелкую копию.

    >>> a = ['spam']
    >>> b = a[:]
    >>> b
    ['spam']
    >>> a is b
    False
    

Вот полный пример с эквивалентным кодом Python, аннотированным в комментариях.

#include <iostream>
#include <boost/python.hpp>

/// @brief Mockup class.
struct other_class
{
  boost::python::list py_list;
};

/// @brief Helper function to print object id and its string representation.
std::string to_string(boost::python::object& o)
{
  std::stringstream stream;
  stream << o.ptr() << " = "
         << boost::python::extract<std::string>(o.attr("__str__")())();
  return stream.str();
}

int main()
{
  using std::cout;
  using std::endl;
  namespace python = boost::python;

  Py_Initialize();
  try
  {
    python::object object;                            // object = None
    cout << to_string(object) << "\n"                 // print object
         << "  is none check: " << object.is_none()   // print object is None
         << endl;

    // Create other_class and populate its list.
    other_class* c = new other_class();               // py_list = []
    cout << "c->py_list: " << to_string(c->py_list)   // print py_list
         << endl;
    c->py_list.append("spam");                        // py_list.append("spam")
    cout << "c->py_list: " << to_string(c->py_list)   // print py_list
         << endl;

    // Have list1 reference c->py_list.
    python::list list1;                                // list1 = []
    cout << "list1: " << to_string(list1) << "\n"      // print list1
         << "assign py_list to list1" << endl;
    list1 = c->py_list;                                // list1 = py_list
    cout << "list1: " << to_string(list1) << endl;     // print list1

    // Modify list1 and observe effects on pylist.
    cout << "modify list1" << endl;
    list1.append(42);                                 // list1.append(42)
    cout << "c->py_list: " << to_string(c->py_list)   // print py_list
         << endl;

    // Shallow-copy list1.
    cout << "copying list1 into list2" << endl;
    python::list list2(
        list1.slice(python::_, python::_));            // list2 = list1[:]
    list2.append("eggs");                              // list2.append("eggs")
    cout << "list2: " << to_string(list2) << "\n"      // print list2
         << "list1: " << to_string(list1) << endl;     // print list1

    delete c;
  }
  catch (python::error_already_set&)
  {
    PyErr_Print();
  }
}

Вывод:

0x804e1ac = None
  is none check: 1
c->py_list: 0xb707024c = []
c->py_list: 0xb707024c = ['spam']
list1: 0xb70da98c = []
assign py_list to list1
list1: 0xb707024c = ['spam']
modify list1
c->py_list: 0xb707024c = ['spam', 42]
copying list1 into list2
list2: 0xb707cb0c = ['spam', 42, 'eggs']
list1: 0xb707024c = ['spam', 42]

Несколько замечаний в выводе:

  • По умолчанию сконструированы boost::python::list objects управляют ссылкой на пустой список. 0x804e1ac - None, и ни один из внутренних указателей PyObject объекта списка не ссылается на него.
  • list1 = py_list назначение вызывает list1 управлять ссылку на тот же список, управляемый py_list. Это проявляется в выходе по list1 первоначально управлениям ссылкой на 0xb70da98c, но после присваивания, он управляет ссылкой на 0xb707024c. С list1 и py_list управления тем же списком, изменение списка с помощью одной ручки можно наблюдать в другой ручке.
  • Нарезка построила новый список. Таким образом, PyObject внутренняя точка для list2 управляет другой ссылки (0xb707cb0c), чем list1 указатель (0xb707024c).
  • 0
    спасибо, я немного отредактировал пост

Ещё вопросы

Сообщество Overcoder
Наверх
Меню