问题不在于赋值运算符,问题在于py_list
' 的内部PyObject
指针是nullptr
. 在大多数情况下,指针不应为空。从 Python 的角度来看,它至少应该管理对 PythonNone
对象的引用,就像它通过默认构造的boost::python::object
. 的默认构造函数boost::python::list
创建一个新的空列表。因此,问题的根源可能存在于other_class
的构造函数或“某些代码”块中。
为了详细说明标题中提出的问题,在 Boost.Python 中创建引用或复制列表与在 Python 中相同:
这是一个完整的示例,其中包含注释中注释的 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
的对象管理对空列表的引用。 0x804e1ac
is None
,并且列表对象的内部PyObject
指针都不管理对它的引用。
- 该
list1 = py_list
分配导致list1
管理对由 管理的同一列表的引用py_list
。这通过list1
最初管理对 的引用在输出中展示0xb70da98c
,但在分配后,它管理对 的引用0xb707024c
。使用list1
并py_list
管理同一个列表,通过一个句柄对列表的更改可以在另一个句柄中观察到。
- 切片构造了一个新列表。因此,
PyObject
内部点 forlist2
管理的引用 ( 0xb707cb0c
) 与list1
的指针 ( 0xb707024c
) 不同。