class inheritance

JLundell jlundell at pobox.com
Fri Dec 17 17:19:54 EST 2010


On Saturday, March 13, 2010 9:03:36 AM UTC-8, Jonathan Lundell wrote:
> I've got a subclass of fractions.Fraction called Value; it's a mostly
> trivial class, except that it overrides __eq__ to mean 'nearly equal'.
> However, since Fraction's operations result in a Fraction, not a
> Value, I end up with stuff like this:
> 
> x = Value(1) + Value(2)
> 
> where x is now a Fraction, not a Value, and x == y uses
> Fraction.__eq__ rather than Value.__eq__.
> 
> This appears to be standard Python behavior (int does the same thing).
> I've worked around it by overriding __add__, etc, with functions that
> invoke Fraction but coerce the result. But that's tedious; there are a
> lot of methods to override.
> 
> So I'm wondering: is there a more efficient way to accomplish what I'm
> after?

I recently implemented a different approach to this. I've got:

class Rational(fractions.Fraction):

... and some methods of my own, including my own __new__ and __str__ (which is one of the reasons I need the class). Then after (outside) the class definition, this code that was inspired by something similar I noticed in Python Cookbook. There are two things going on here. One is, of course, the automation at import time. The other is that the wrapper gets a Fraction instance and simply overrides __class__, rather than creating yet another Rational and unbinding the interim Fraction. Seems to work quite well.

# create wrappers for Rational methods that return Rational (not Fraction) objects
#
def _wrap_method(method):
    "wrap a Fraction method in Rational"
    fraction_method = getattr(Fraction, method)
    def x(*args):
        "call Fraction and change result to Rational"
        v = fraction_method(*args)
        v.__class__ = Rational
        return v
    x.func_name = method
    setattr(Rational, method, x)

for name in "pos neg abs trunc".split():
    _wrap_method("__%s__" % name)   # wrap method, eg __pos__

for name in "add sub mul div truediv floordiv mod pow".split():
    _wrap_method("__%s__" % name)   # wrap method, eg __add__
    _wrap_method("__r%s__" % name)  # wrap reversed-argument method, eg __radd__

del _wrap_method



More information about the Python-list mailing list