Передача «указателя на виртуальную функцию» как аргумент в Python

Сравните следующий код в 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);
}

И в питон:

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)

C ++ код напечатает:

one
two

в то время как питон код напечатает

one
one

Как я могу передать «указатель на метод» и преобразовать его в переопределенный, достигнув того же поведения в Python, что и в C ++?

Чтобы добавить некоторый контекст и объяснить, почему я изначально думал об этом шаблоне. У меня есть дерево, состоящее из узлов, которые можно разделить на подклассы. Я хотел бы создать общую функцию обхода графа, которая принимает узел графа, а также функцию, которая может быть переопределена в подклассах узлов графа. Функция вычисляет некоторое значение для узла, учитывая значения, рассчитанные для соседних узлов. Цель состоит в том, чтобы вернуть значение, рассчитанное для данного узла (которое требует обхода всего графа).

11

Решение

Что касается вашего редактирования, то вы можете использовать маленькую лямбду-обертку, которая вызывает метод, на который вы хотите сослаться. Таким образом, вызов метода выглядит как «обычный код Python», а не как нечто сложное, основанное на доступе на основе строк.

В вашем примере единственная часть, которую нужно изменить, это вызов test функция:

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

Другие решения

Следующее производит вывод, который вы хотите:

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

class B(A):
def bar(self):
print("two")

def test(objs, funcname):
noop = lambda: None
for o in objs:
getattr(o, funcname, noop)()

objs = [A(), B()]
test(objs, "bar")
4

По вопросам рекламы [email protected]