Представьте, что я определяю два класса (Foo
и Bar
). Bar
сохраняет два Foo
с в std::vector
как std::shared_ptr
с. Я хочу показать все на Python с помощью pybind11
. Кроме того, я хочу, чтобы Foo
также поддерживал динамические атрибуты, что требует использования pybind11::dynamic_attr()
на этапе привязки. Все работает нормально, пока я не пытаюсь добавлять динамические атрибуты к экземплярам Foo
только через вектор, который их хранит. Поскольку нелегко объяснить мою проблему словами, вот MWE:
Модуль pybind11
определен в файле pyissue.cpp
:
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
#include <memory>
namespace py = pybind11;
class Foo {
public:
Foo() {
a = 5;
}
~Foo() {
}
int a;
};
class Bar {
public:
Bar() {
foos.push_back(std::make_shared<Foo>());
foos.push_back(std::make_shared<Foo>());
}
~Bar() {
}
std::vector<std::shared_ptr<Foo>> foos;
};
PYBIND11_MODULE(pybug, m) {
py::class_<Foo, std::shared_ptr<Foo>> foo(m, "Foo", py::dynamic_attr());
foo
.def(py::init<>())
.def_readwrite("a", &Foo::a);
py::class_<Bar> bar(m, "Bar");
bar
.def(py::init<>())
.def_readwrite("foos", &Bar::foos);
, который можно скомпилироватьследующим образом (по крайней мере, на моем компьютере с Linux):
g++ pyissue.cpp -shared --std=c++11 -fPIC `python3 -m pybind11 --includes` -o pyissue`python3-config --extension-suffix`
Теперь следующий фрагмент кода Python работает точно так же, как и предполагалось:
import pyissue
bar = pyissue.Bar()
print(bar.foos[0].a) # prints 5
bar.foos[0].a = 2
print(bar.foos[0].a) # prints 2
myfoo = bar.foos[0]
myfoo.b = 3 # this is a dynamic attribute, it exists only on python's side
print(myfoo.b) # prints 3
Однако следующий фрагмент кода вызывает исключение AttributeError: 'pybug.Foo' object has no attribute 'b'
:
import pyissue
bar = pyissue.Bar()
bar.foos[0].b = 2
print(b.foos[0].b) # here comes the exception
Мой вопрос сводится к следующему: есть ли способ заставить последний фрагмент работать?
Редактировать : обратите внимание, что если я явно сохраню ссылку наобъект, то я могу использовать его без каких-либо проблем. Например, следующий код будет работать как положено:
import pyissue
bar = pyissue.Bar()
myfoo = bar.foos[0]
bar.foos[0].b = 2
print(b.foos[0].b) # prints 2