[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

class inheritance

JLundell

3/13/2010 5:04:00 PM

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?
15 Answers

Patrick Maupin

3/13/2010 5:09:00 PM

0

On Mar 13, 11:03 am, JLundell <jlund...@pobox.com> 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?

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#59289c...

HTH,
Pat

Jack Diederich

3/13/2010 5:38:00 PM

0

On Sat, Mar 13, 2010 at 12:03 PM, JLundell <jlundell@pobox.com> 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?

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

3/13/2010 5:45:00 PM

0

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

3/13/2010 6:11:00 PM

0

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

3/13/2010 8:27:00 PM

0

On Mar 13, 9:03 am, JLundell <jlund...@pobox.com> 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?

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

3/15/2010 6:25:00 PM

0

JLundell 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 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

3/15/2010 11:35:00 PM

0

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

3/16/2010 1:03:00 AM

0

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

3/16/2010 12:36:00 PM

0



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

3/16/2010 3:06:00 PM

0

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