class inheritance

J

JLundell

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?
 
P

Patrick Maupin

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...en&lnk=gst&q=pmaupin+userint#59289c16603fb374

HTH,
Pat
 
J

Jack Diederich

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
 
P

Patrick Maupin

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
 
J

JLundell

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).
 
C

Carl Banks

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
 
J

Jean-Michel Pichavant

JLundell said:
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
 
J

JLundell

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.
 
C

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.

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
 
D

Dave Angel

Carl said:
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.
 
R

Robert Kern

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
 
J

JLundell

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.

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.
 
R

Robert Kern

APL scaled their fuzz to the larger of the values being compared.

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.

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

Dennis Lee Bieber

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.

I didn't do enough with APL back in 1980 to get to that point (I
needed 2 credits to graduate, so took a 3 credit independent study of
APL -- where my biggest program was to turn a Tektronix storage display
terminal into the worlds most expensive Etch-a-Sketch)

REXX has a similar (from the Regina manual):

"""
The NUMERIC statement is used to control most aspects of arithmetic
operations. It has three distinct forms: DIGITS, FORM and FUZZ; which to
choose is given by the second token in the instruction:

DIGITS
Is used to set the number of significant digits in arithmetic
operations. The initial value is 9, which is also the default value if
expr is not specified. Large values for DIGITS tend to slow down some
arithmetic operations considerably. If specified, expr must be a
positive integer.

FUZZ
Is used in numeric comparisons, and its initial and default value is
0. Normally, two numbers must have identical numeric values for a number
of their most significant digits in order to be considered equal. How
many digits are considered is determined by DIGITS. If DIGITS is 4, then
12345 and 12346 are equal, but not 12345 and 12356. However, when FUZZ
is nonzero, then only the DIGITS minus FUZZ most significant digits are
checked. E.g. if DIGITS is 4 and FUZZ are 2, then 1234 and 1245 are
equal, but not 1234 and 1345.
The value for FUZZ must be a nonnegative integer, and less than the
value of DIGITS. FUZZ is seldom used, but is useful when you want to
make comparisons less influenced by inaccuracies. Note that using with
values of FUZZ that is close to DIGITS may give highly surprising
results.
"""
 
J

JLundell

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.

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top