
OK, I implemented __pow__, compose, __rmul__, __rsub__, and __radd__. The implementation of __pow__ does not take advantage of the binomial theorem or its higher-order generalizations, mostly because I don't know the higher-order generalizations.
Great. I'd done a __pow__ earlier, but I like yours better. I also make sure the exponent is non-negative, as we're not promising to handle that kind of algebra here.
I also did the type check thing so that integer constants are automatically converted to polynomials where appropriate. That means it would be possible to implement __neg__ as "return self * -1".
This is good -- I've incorporated it.
(This version gets rid of list comprehensions, +=, and -=, so it will run under 1.5.2.)
My most recent at: http://www.inetarena.com/~pdx4d/ocn/python/polynomial.html or same w/ .py extension for cut and paste source. Note that for commutative ops like __add__ and __mul__, you can just go __radd__ = __add__ and __rmul__ = __mul__ to create equivalent definitions. Only subtraction needs to be handled differently, because arg order matters. Also, once your enhancements are added, you really don't need a separate compose method (which is very cool). Just pass a polynomial as your "value of x" in the already-defined call method:
from polynomial import * f = Poly([1,-3,2]) g = Poly([1,3,0]) f x**2 - 3*x + 2 g x**2 + 3*x f(g) # <--- symbolic composition x**4 + 6*x**3 + 6*x**2 - 9*x + 2 g(f) # <--- symbolic composition x**4 - 6*x**3 + 16*x**2 - 21*x + 10 f(g(10)) # <--- or you can do numeric evaluation 16512 g(f(10)) 5400
I've put your name in lights in my program's marquee. Kirby