开发者

Override __mul__ from a child class using parent implementation: leads to problems

开发者 https://www.devze.com 2023-01-26 06:15 出处:网络
I\'m trying to implement the __mul__ method 开发者_开发问答of class C which extends class P. Class P has an implementation of __mul__ but that\'s only for elements of that type (P() * P()).

I'm trying to implement the __mul__ method 开发者_开发问答of class C which extends class P. Class P has an implementation of __mul__ but that's only for elements of that type (P() * P()).

So in C.__mul__ I want to implement simple multiplication for a float when the argument is float. When it's not I want to use P.__mul__ ... but that leads to problems as in P.__mul__ that's a return P(something)...

So basically the fact that they were originally of type C is lost after some operations.

The following code better explain the issue.

Any idea fix this?

class MyFloat(object):
  def __init__(self, a):
    self.a = a

  def __mul__(self, other):
    return MyFloat(self.a * other.a)

  def __repr__(self):
    return str(self.a)


class MyFloatExt(MyFloat):
  def __init__(self, a):
    MyFloat.__init__(self, a)

  def __add__(self, other):
    return MyFloatExt(self.a + other.a)

  def __mul__(self, other):
    if type(other) == (int, long, float):
      return MyFloatExt(self.a * other)
    else:
      return MyFloat.__mul__(self, other)

a = MyFloatExt(0.5)
b = MyFloatExt(1.5)

c = a + b
print c

d = a * b
print d

e = d * c
print e

print isinstance(e, MyFloat)
f = e * 0.5
print f


First you your typecheck in __mul__ for MyFloatExt should look like

isinstance(other,(int,long,float))

or even better

isinstance(other,Number) #from numbers import Number

Also you would like to change definition of __mul__ in MyFloat to this:

class MyFloat(object):
#...
  def __mul__(self, other):
    return type(self)(self.a * other.a)
#...

so it can create instances of your actual type

And you can prefer call super instead of calling MyFloat.__mul__ with reasons of evolution your type hierarchies.

full source:

from numbers import Number
class MyFloat(object):
  def __init__(self, a):
    self.a = a

  def __mul__(self, other):
    return type(self)(self.a * other.a)

  def __repr__(self):
    return str(self.a)


class MyFloatExt(MyFloat):
  def __init__(self, a):
    super(MyFloatExt,self).__init__(a)

  def __add__(self, other):
    return type(self)(self.a + other.a)

  def __mul__(self, other):
    if isinstance(other,Number):
      return type(self)(self.a * other)
    else:
      return super(MyFloatExt,self).__mul__(other)


a = MyFloatExt(0.5)
b = MyFloatExt(1.5)

c = a + b
print c

d = a * b
print d


e = d * c
print e

print isinstance(e, MyFloat)

f = e * 0.5
print f

print map(type,[a,b,c,d,e,f]) == [MyFloatExt]*6


Two problems here

  1. In your __mul__ implementation of MyFloatExt you're never checking if other is an instance of MyFloatExt

  2. isinstance(e, MyFloat) will always be true, because MyFloatExt inherits from MyFloat

To fix it:

def __mul__(self, other):

    # check if we deal with a MyFloatExt instance
    if isinstance(other, MyFloatExt):
        return MyFloatExt(self.a * other.a)

    if type(other) == (int, long, float):
        return MyFloatExt(self.a * other)

    else:
        return MyFloat.__mul__(self, other)

# do the correct check
print isinstance(e, MyFloatExt)
0

精彩评论

暂无评论...
验证码 换一张
取 消