And And - 4 months ago 8
C++ Question

Passing a "pointer to a virtual function" as argument in Python

Compare the following code in C++:

#include <iostream>
#include <vector>

struct A
{
virtual void bar(void) { std::cout << "one" << std::endl; }
};

struct B : public A
{
virtual void bar(void) { std::cout << "two" << std::endl; }
};

void test(std::vector<A*> objs, void (A::*fun)())
{
for (auto o = objs.begin(); o != objs.end(); ++o)
{
A* obj = (*o);
(obj->*fun)();
}
}

int main()
{
std::vector<A*> objs = {new A(), new B()};

test(objs, &A::bar);
}


and in Python:

class A:

def bar(self):
print("one")


class B(A):

def bar(self):
print("two")


def test(objs, fun):
for o in objs:
fun(o)

objs = [A(), B()]
test(objs, A.bar)


The C++ code will print:

one
two


while the Python code will print

one
one


How can I pass a pointer to a method and resolve it to the overridden one, achieving the same behavior in Python as in C++?

EDIT:

To add some context and explain why I initially thought about this pattern. I have a tree consisting of nodes that can be subclassed. I would like to create a generic graph traversal function which takes a node of the graph as well as a function which might be overridden in subclasses of graph nodes. The function calculates some value for a node, given values calculated for adjacent nodes. The goal is to return a value calculated for the given node (which requires traversing the whole graph).

Answer

Regarding your edit, one thing you could do is use a little wrapper lambda that calls the method you want to reference. This way the method call looks like "regular python code" instead of being something complicated based on string-based access.

In your example, the only part that would need to change is the call to the test function:

test(objs, (lambda x: x.bar()))