Я, наверное, здесь упускаю что-то очевидное. У меня есть простая иерархия классов, которая выглядит примерно так:
class Any:
def op2_additive_add(self, other: 'Any') -> 'Any':
raise NotImplementedError
def op2_multiplicative_multiply(self, other: 'Any') -> 'Any':
raise NotImplementedError
def op2_exponential_power(self, other: 'Any') -> 'Any':
raise NotImplementedError
# A dozen of similar methods not shown
class Rational(Any):
def op2_additive_add(self, other: 'Any') -> 'Rational':
pass # Implementation not shown
def op2_multiplicative_multiply(self, other: 'Any') -> 'Rational':
pass # Implementation not shown
def op2_exponential_power(self, other: 'Any') -> 'Rational':
pass # Implementation not shown
class Set(Any):
def op2_additive_add(self, other: 'Any') -> 'Set':
pass # Implementation not shown
def op2_multiplicative_multiply(self, other: 'Any') -> 'Set':
pass # Implementation not shown
def op2_exponential_power(self, other: 'Any') -> 'Set':
pass # Implementation not shown
# Half a dozen of similar derived types not shown.
Я реализую класс диспетчера, который должен выбирать запрошенную операцию с двумя операндами, не зная их типов, и затем передавать ссылку на правильный метод исполнителю. Примерно так (код ниже не будет работать):
def select_operator(selector) -> typing.Callable[[Any, Any], Any]:
if selector.such_and_such():
return Any.op2_additive_add
elif selector.so_and_so():
return Any.op2_exponential_power
# And so on
Приведенный выше код не будет работать, потому что попытка вызвать возвращенный несвязанный метод обойдет динамическую диспетчеризацию; то есть select_operator(selector)(foo, bar)
всегда будет выбрасывать NotImplementedError
.
Лучшее решение, которое я мог бы найти до сих пор, примерно так, и это не очень красиво:
def select_operator(selector) -> str:
if selector.such_and_such():
return Any.op2_additive_add.__name__
elif selector.so_and_so():
return Any.op2_exponential_power.__name__
# And so on
method_name = select_operator(selector)
getattr(foo, method_name)(bar)
TL; DR: как отложить процесс динамической отправки до тех пор, пока я не получу ссылку на метод?