Сравните следующий код в 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 ++?
Чтобы добавить некоторый контекст и объяснить, почему я изначально думал об этом шаблоне. У меня есть дерево, состоящее из узлов, которые можно разделить на подклассы. Я хотел бы создать общую функцию обхода графа, которая принимает узел графа, а также функцию, которая может быть переопределена в подклассах узлов графа. Функция вычисляет некоторое значение для узла, учитывая значения, рассчитанные для соседних узлов. Цель состоит в том, чтобы вернуть значение, рассчитанное для данного узла (которое требует обхода всего графа).
Что касается вашего редактирования, то вы можете использовать маленькую лямбду-обертку, которая вызывает метод, на который вы хотите сослаться. Таким образом, вызов метода выглядит как «обычный код Python», а не как нечто сложное, основанное на доступе на основе строк.
В вашем примере единственная часть, которую нужно изменить, это вызов test
функция:
test(objs, (lambda x: x.bar()))
Следующее производит вывод, который вы хотите:
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")