[BUG]: send a python function to c++ as a std::function to create Python subclass instance,the constructor of python class be called but the instance still the base class
Open
Nobody has claimed this yet.
triage
- Dominant language
- C++
- Stars
- 18k
- Forks
- 2.3k
- Avg merge
- 5d 17h
- Merged PRs (30d)
- 10
Description
Required prerequisites
- Make sure you've read the documentation. Your issue may be addressed there.
- Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
- Consider asking first in the Gitter chat room or in a Discussion.
What version (or hash if on master) of pybind11 are you using?
2.10.4
Problem description
- my cpp code
class Pet {
public:
Pet()
{
id = makePetId();
printf("Pet::Pet\n");
}
virtual ~Pet() { printf("Pet::~Pet\n"); }
Pet(const Pet&) = delete;
Pet(const Pet&&) = delete;
virtual std::string name() const { return "pet"; }
static int makePetId()
{
static int id = 0;
return id++;
}
int id = -1;
};
class PyPet : public Pet {
public:
using Pet::Pet;
std::string name() const override { PYBIND11_OVERRIDE(std::string, Pet, name, ); }
};
class PetRoom {
public:
PetRoom() = default;
void echoPetName(std::shared_ptr<Pet> pet) { printf("pet name: %s\n", pet->name().c_str()); }
void addPet(std::shared_ptr<Pet> pet)
{
printf("add pet: %s\n", pet->name().c_str());
pets.push_back(pet);
}
void addPetCustom(std::function<std::shared_ptr<Pet>()> petGenerator)
{
auto pet = petGenerator();
printf("add pet custom: %s\n", pet->name().c_str());
pets.push_back(pet);
}
std::vector<std::shared_ptr<Pet>> pets;
};
py::class_<Pet, PyPet, std::shared_ptr<Pet>>(m, "Pet")
.def(py::init<>()).def("name", &Pet::name)
.def_readonly("id", &PyPet::id);
py::class_<PetRoom>(m, "PetRoom")
.def(py::init<>())
.def("echoPetName", &PetRoom::echoPetName)
.def("addPet", &PetRoom::addPet)
.def("addPetCustom", &PetRoom::addPetCustom)
// .def_readwrite("pets", &PetRoom::pets);
.def_readwrite("pets", &PetRoom::pets, py::return_value_policy::reference);
- my python code
import libpybind
import unittest
class Dog(libpybind.Pet):
@staticmethod
def create():
print("create python dog")
return Dog()
def __init__(self):
print("construct python dog")
libpybind.Pet.__init__(self)
def name(self):
return "dog"
class TestClass(unittest.TestCase):
def setUp(self):
self.petRoom = libpybind.PetRoom()
return super().setUp()
def test_if_functional_right(self):
# self.skipTest("skip test_if_functional_right")
self.petRoom.addPetCustom(Dog.create)
for pet in self.petRoom.pets:
print("name={},id={}".format(pet.name(), pet.id))
if __name__ == "__main__":
unittest.main()
- result
create python dog
construct python dog
Pet::Pet
add pet custom: pet
name=pet,id=0
.Pet::~Pet
- my problem
- I use a std::function to create std::shared_ptr,because I want to create python subclass in python
- I send the
Dog.createto thePetRoom.addPetCustom - The
Dog.createbeen called inPetRoom.addPetCustom,but the result shows the inst is still Pet not Dog
Reproducible example code
No response
Is this a regression? Put the last known working version here if it is.
Not a regression
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the PetRoom.addPetCustom binding and the Dog.create callback shown in the issue, then trace how the returned shared_ptr is converted and stored in PetRoom.pets. Reproduce the example and compare the resulting object's type and name() dispatch; done means the stored object remains the Python Dog subclass and reports "dog" rather than "pet".
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, python
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100