Czy wtyczka dodająca nowe metody instancji małpa-łatka lub podklasa / mixin i zastępuje rodzica?
Jako prosty przykład weź klasęPolynomial
class Polynomial(object):
def __init__(self, coefficients):
self.coefficients = coefficients
dla wielomianów formularzap(x) = a_0 + a_1*x + a_2*x^2 + ... + a_n*x^n
gdzie listacoefficients = (a_0, a_1, ..., a_n)
przechowuje te współczynniki.
Jeden moduł wtyczkihorner
może wtedy zapewnić funkcjęhorner.evaluate_polynomial(p, x)
ocenić aPolynomial
instancjap
w wartościx
, tj. zwróć wartośćp(x)
. Ale zamiast dzwonić do funkcji w ten sposób, zadzwoń dop.evaluate(x)
(lub bardziej intuicyjniep(x)
przez__call__
) byłoby lepiej. Ale jak to zrobić?
a) łatanie małpy, tj.
Polynomial.evaluate = horner.evaluate_polynomial
# or Polynomial.__call__ = horner.evaluate_polynomial
b) Klasyfikacja i zastąpienie klasy, tj.
orgPolynomial = Polynomial
class EvaluatablePolynomial(Polynomial):
def evaluate(self, x):
return horner.evaluate_polynomial(self, x)
Polynomial = EvaluatablePolynomial
c) Mixin + Replacing, tj.
orgPolynomial = Polynomial
class Evaluatable(object):
def evaluate(self, x):
return horner.evaluate_polynomial(self, x)
class EvaluatablePolynomial(Polynomial, Evaluatable):
pass
Polynomial = EvaluatablePolynomial
Rzeczywiście, łatanie małp jest najkrótsze (zwłaszcza, że nie uwzględniłem żadnego testu à lahasattr(Polynomial, 'evaluate')
, ale podobnie podklasa powinna zadzwonićsuper()
wtedy ...), ale czy jest to najbardziej Pythonic? A może istnieją inne lepsze alternatywy?
Zwłaszcza biorąc pod uwagę możliwość wielu wtyczek zapewniających tę samą funkcję, np.zeros
albo używającnumpy
lub własnoręcznie wykonana bisekcja, gdzie oczywiście powinna być użyta tylko jedna wtyczka implementująca, który wybór może być mniej podatny na błędy?