Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

class inheritance

21 views
Skip to first unread message

JLundell

unread,
Mar 13, 2010, 12:03:36 PM3/13/10
to
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?

Patrick Maupin

unread,
Mar 13, 2010, 12:09:20 PM3/13/10
to

7 years ago, I had a similar problem for a different and now obsolete
reason. I'm sure my solution could be easily updated though. I wrote
code to write a wrapper class. Sort of a meta-module. Original
reference here:

http://groups.google.com/group/comp.lang.python/browse_frm/thread/1253bbab7dfd4b/59289c16603fb374?hl=en&lnk=gst&q=pmaupin+userint#59289c16603fb374

HTH,
Pat

Jack Diederich

unread,
Mar 13, 2010, 12:37:45 PM3/13/10
to JLundell, pytho...@python.org

If Fraction.__add__ returns a new object but the subclass Value is
compatible (as I would except since it is a sublcass) then just change
all references in Franction.__add__ to be more generic, ex/

class Franction():
def __add__(self, other):
return self.__classs__(self.denominator + other.denominator)

That way if __add__ is called by an instance of a subclass it will
return an instance of that subclass.

-Jack

Patrick Maupin

unread,
Mar 13, 2010, 12:44:38 PM3/13/10
to
On Mar 13, 11:37 am, Jack Diederich <jackd...@gmail.com> wrote:
> If Fraction.__add__ returns a new object but the subclass Value is
> compatible (as I would except since it is a sublcass) then just change
> all references in Franction.__add__ to be more generic, ex/
>
> class Franction():
>   def __add__(self, other):
>     return self.__classs__(self.denominator + other.denominator)
>
> That way if __add__ is called by an instance of a subclass it will
> return an instance of that subclass.
>

Yes, I think the OP understands that, and also understands that he
would have to do the same thing for __sub__, __div__, __rsub__,
__radd__, etc.

That's why I suggested that, instead of writing all that tedious code,
he could write code that writes the tedious code :-)

As Terence Parr of ANTLER fame asks: "Why program by hand in five
days what you can spend five years of your life automating?"

Pat

JLundell

unread,
Mar 13, 2010, 1:11:15 PM3/13/10
to
On Mar 13, 9:37 am, Jack Diederich <jackd...@gmail.com> wrote:
> If Fraction.__add__ returns a new object but the subclass Value is
> compatible (as I would except since it is a sublcass) then just change
> all references in Franction.__add__ to be more generic, ex/
>
> class Franction():
>   def __add__(self, other):
>     return self.__classs__(self.denominator + other.denominator)
>
> That way if __add__ is called by an instance of a subclass it will
> return an instance of that subclass.

That was my first thought, because I had originally assumed that's the
way Fraction worked. However, a) it's easier to do the overriding in
my own class than patching Fraction (or at least no harder), and 2)
Fraction is only doing the same thing that int does, so it's hard to
justify a patch.

I think Patrick's solution might be the tidiest one. I'll give it a
shot (thanks, Patrick).

Carl Banks

unread,
Mar 13, 2010, 3:26:45 PM3/13/10
to

It's a tad unfortunately Python doesn't make this easier. If I had to
do it more than once I'd probably write a mixin to do it:

class ArithmeticSelfCastMixin(object):
def __add__(self,other):
return
self.__class__(super(ArithmeticSelfCastMixin,self).__add__(other)
# etc.


class Value(ArithmeticSelfCastMixin,fraction.Fraction):
pass


However, I want to warn you about overriding __eq__ to mean "almost
equal": it can have unexpected results so I don't recommend it. Two
of the main issues with it are:

1. It violates the transitive property ("If A == B and B == C, then A
== C") which most programmers expect to be true.

2. It will give unpredictable results when the objects are used in
sets or as dictionary keys. Those thow types expect the transitive
property to be true. If you are going to redefine __eq__ to mean
"almost equal", then at least define __hash__ to raise
NotImplementedError so that Python will refuse to use them in sets or
as dictionary keys:

def __hash__(self): raise NotImplementedError


Carl Banks

Jean-Michel Pichavant

unread,
Mar 15, 2010, 2:24:38 PM3/15/10
to JLundell, pytho...@python.org
I would change the approach.
To the question, "*is* a Value a Fraction", some may tempted to answer
"No" (for instance, a fraction has a denominator, a value has not).
However "Does a Fraction *have* a Value", you could possibly say "Yes".

The value may be then an attribute of the class Fraction, not a subclass.
To test fraction equality, use F1 == F2. In order to test 'nearly
equality', use F1.val() == F2.val().

JM


JLundell

unread,
Mar 15, 2010, 7:34:35 PM3/15/10
to
On Mar 13, 1:26 pm, Carl Banks <pavlovevide...@gmail.com> wrote:
> It's a tad unfortunately Python doesn't make this easier.  If I had to
> do it more than once I'd probably write a mixin to do it:
>
> class ArithmeticSelfCastMixin(object):
>     def __add__(self,other):
>         return
> self.__class__(super(ArithmeticSelfCastMixin,self).__add__(other)
>     # etc.
>
> class Value(ArithmeticSelfCastMixin,fraction.Fraction):
>     pass
>
> However, I want to warn you about overriding __eq__ to mean "almost
> equal": it can have unexpected results so I don't recommend it.  Two
> of the main issues with it are:
>
> 1. It violates the transitive property ("If A == B and B == C, then A
> == C") which most programmers expect to be true.
>
> 2. It will give unpredictable results when the objects are used in
> sets or as dictionary keys.  Those thow types expect the transitive
> property to be true.  If you are going to redefine __eq__ to mean
> "almost equal", then at least define __hash__ to raise
> NotImplementedError so that Python will refuse to use them in sets or
> as dictionary keys:
>
>     def __hash__(self): raise NotImplementedError
>
> Carl Banks

It's also unfortunate that Python doesn't have an approximately-equal
operator; it'd come in handy for floating-point applications while
preserving hash. If only there were a ~= or ≈ operator I could
overload. And ~ is unary, so no joy.

My application is in that sense a little like a floating-point app, in
that it needs approximately-equal. And it doesn't need Value to be
hashable; thanks for the NotImplementedError suggestion; I've done
that as a safeguard.

Carl Banks

unread,
Mar 15, 2010, 9:03:15 PM3/15/10
to
On Mar 15, 4:34 pm, JLundell <jlund...@pobox.com> wrote:
> It's also unfortunate that Python doesn't have an approximately-equal
> operator; it'd come in handy for floating-point applications while
> preserving hash. If only there were a ~= or ≈ operator I could
> overload. And ~ is unary, so no joy.

One problem with it is that there's no way to make it universal;
different appiplications have different ideas of close. Conceivably
it could be usefully defined for a user type though..

Bacause of this problem almost no languages have an almost equal
operator. I'm curious what languages do, of if there are any with a
trinary operator that also takes a threshold.

Carl Banks

Dave Angel

unread,
Mar 16, 2010, 8:35:54 AM3/16/10
to Carl Banks, pytho...@python.org

Carl Banks wrote:
> On Mar 15, 4:34 pm, JLundell <jlund...@pobox.com> wrote:
>
>> It's also unfortunate that Python doesn't have an approximately-equal
>> operator; it'd come in handy for floating-point applications while

>> preserving hash. If only there were a ~=r ≈ operator I could


>> overload. And ~ is unary, so no joy.
>>
>
> One problem with it is that there's no way to make it universal;
> different appiplications have different ideas of close. Conceivably
> it could be usefully defined for a user type though..
>
> Bacause of this problem almost no languages have an almost equal
> operator. I'm curious what languages do, of if there are any with a
> trinary operator that also takes a threshold.
>
> Carl Banks
>
>

If I recall correctly, APL has a *fuzz* value, which is used in all(?)
comparisons. But I do not recall anything about how it was defined. I do
recall that you could change the threshold, and suspect it was relative
to the operands. For symmetry, it would probably have to be relative to
the average of the two values, or some such.

Robert Kern

unread,
Mar 16, 2010, 11:06:10 AM3/16/10
to pytho...@python.org
On 2010-03-16 07:35 AM, Dave Angel wrote:

>
>
> Carl Banks wrote:
>> On Mar 15, 4:34 pm, JLundell <jlund...@pobox.com> wrote:
>>> It's also unfortunate that Python doesn't have an approximately-equal
>>> operator; it'd come in handy for floating-point applications while
>>> preserving hash. If only there were a ~=r ≈ operator I could

>>> overload. And ~ is unary, so no joy.
>>
>> One problem with it is that there's no way to make it universal;
>> different appiplications have different ideas of close. Conceivably
>> it could be usefully defined for a user type though..
>>
>> Bacause of this problem almost no languages have an almost equal
>> operator. I'm curious what languages do, of if there are any with a
>> trinary operator that also takes a threshold.
>>
>> Carl Banks
>>
> If I recall correctly, APL has a *fuzz* value, which is used in all(?)
> comparisons. But I do not recall anything about how it was defined. I do
> recall that you could change the threshold, and suspect it was relative
> to the operands. For symmetry, it would probably have to be relative to
> the average of the two values, or some such.

The problem is that frequently there is no system-wide fuzz value which is
appropriate for all comparisons in a given program. You need to choose the right
value for each comparison. Consequently, you might as well use a function
instead of an operator and a global variable.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

JLundell

unread,
Mar 16, 2010, 6:55:17 PM3/16/10
to

APL scaled their fuzz to the larger of the values being compared. In
my case, my domain permits me to use a constant fuzz; all my units are
the same (votes, as it happens). I've seen abs(a/b-1) used instead of
abs(a-b); obviously you'd need to treat comparison with zero
specially.

But yeah, it's really a domain-specific problem.

Robert Kern

unread,
Mar 16, 2010, 7:32:04 PM3/16/10
to pytho...@python.org

I know. My statement stands for relative fuzz values as well as it does for
absolute fuzz values. :-)

> In
> my case, my domain permits me to use a constant fuzz; all my units are
> the same (votes, as it happens). I've seen abs(a/b-1) used instead of
> abs(a-b); obviously you'd need to treat comparison with zero
> specially.

One usually uses a combination of relative and absolute tolerances to account
for the case when the values are close to zero.

> But yeah, it's really a domain-specific problem.

Right. And a single program might need to deal with multiple domains, so a
single global setting to control a language feature is pretty fragile.

Message has been deleted

Steven D'Aprano

unread,
Mar 17, 2010, 8:12:14 PM3/17/10
to
On Mon, 15 Mar 2010 16:34:35 -0700, JLundell wrote:

> It's also unfortunate that Python doesn't have an approximately-equal
> operator; it'd come in handy for floating-point applications while
> preserving hash. If only there were a ~= or ≈ operator I could overload.
> And ~ is unary, so no joy.

Not everything needs to be a built-in, or an operator. This might be
useful for you:

http://code.activestate.com/recipes/577124-approximately-equal/


Feedback welcome.


--
Steven

JLundell

unread,
Mar 18, 2010, 2:01:18 PM3/18/10
to
On Mar 17, 5:12 pm, Steven D'Aprano

Thanks, Steven. I'd considered and rejected that a while ago, but on
reconsideration it's sounding like a better idea. Aside from
preserving the semantics of =, it makes the use of approximate
equality explicit in the code, and that's a plus for what I'm doing.
I'll give it a shot.

JLundell

unread,
Dec 17, 2010, 5:19:54 PM12/17/10
to

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

Ethan Furman

unread,
Dec 21, 2010, 12:21:17 PM12/21/10
to pytho...@python.org
JLundell wrote:
> 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.

[snip]

Another option is to use a metaclass:

class Perpetuate(ABCMeta):
def __new__(metacls, cls_name, cls_bases, cls_dict):
if len(cls_bases) > 1:
raise TypeError("multiple bases not allowed")
result_class = type.__new__(metacls, cls_name,
cls_bases, cls_dict)
base_class = cls_bases[0]
known_attr = set()
for attr in cls_dict.keys():
known_attr.add(attr)
for attr in base_class.__dict__.keys():
if attr in ('__new__'):
continue
code = getattr(base_class, attr)
if callable(code) and attr not in known_attr:
setattr(result_class, attr,
metacls._wrap(base_class, code))
elif attr not in known_attr:
setattr(result_class, attr, code)
return result_class
@staticmethod
def _wrap(base, code):
def wrapper(*args, **kwargs):
if args:
cls = args[0]
result = code(*args, **kwargs)
if type(result) == base:
return cls.__class__(result)
elif isinstance(result, (tuple, list, set)):
new_result = []
for partial in result:
if type(partial) == base:
new_result.append(cls.__class__(partial))
else:
new_result.append(partial)
result = result.__class__(new_result)
elif isinstance(result, dict):
for key in result:
value = result[key]
if type(value) == base:
result[key] = cls.__class__(value)
return result
wrapper.__name__ = code.__name__
wrapper.__doc__ = code.__doc__
return wrapper


then the actual class becomes:

class CloseFraction(Fraction):
__metaclass__ = Perpetuate
def __eq__(x, y):
return abs(x - y) < 1 # season to taste
def __repr__(x):
return "CloseFraction(%d, %d)" % (x.numerator, x.denominator)

Perpetuate needs to handle multiple inheritance better, but it might
meet your needs at this point.

Sample run:
--> n = CloseFraction(3, 2)
--> n
CloseFraction(3, 2)
--> print n
3/2
--> m = CloseFraction(9, 4)
--> m
CloseFraction(9, 4)
--> n == m
True
--> n - m
CloseFraction(-3, 4)
--> n + m
CloseFraction(15, 4)
--> n.real
CloseFraction(3, 2)
--> n.imag
0 # this is an int

Hope this helps!

~Ethan~

JLundell

unread,
Dec 23, 2010, 6:21:42 PM12/23/10
to pytho...@python.org
That's nice, Ethan, especially in that it saves having to explicitly find and list all the methods being covered. It's perhaps not quite so critical for a Fraction-based class, since the set of methods to be covered is fairly well contained, but that's not always going to be the case.

The approach I mentioned earlier (rebinding __class__) is a little faster, since it avoids a call to __new__, but the difference is no doubt negligible in this example, since rational arithmetic isn't exactly lightning fast.

Thanks.

JLundell

unread,
Dec 23, 2010, 6:21:42 PM12/23/10
to comp.lan...@googlegroups.com, pytho...@python.org
0 new messages