关于python:使用父实现覆盖子类中的__mul__:导致问题

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

我正在尝试实现类C的_uuumul_uuuu方法,它扩展了类P。类P有一个_uuuumul_uuu的实现,但这只适用于该类型的元素(p()*p())。

所以在c_uuumul中,当参数为float时,我想为float实现简单的乘法。如果不是的话,我想用P's_uuuuuuuuuuu。但这会导致一些问题,如P's_uuuuumul_uuuuuuuu,这是一个"返回P(某物)"。

所以基本上,它们最初是C型的,在一些操作之后会丢失。

下面的代码可以更好地解释这个问题。

有办法解决这个吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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


首先,您在__mul__中为MyFloatExt输入的类型检查应该是

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

甚至更好

1
isinstance(other,Number) #from numbers import Number

另外,您想将MyFloat__mul__的定义更改为:

1
2
3
4
5
class MyFloat(object):
#...
  def __mul__(self, other):
    return type(self)(self.a * other.a)
#...

因此它可以创建实际类型的实例

您可以选择调用super,而不是调用MyFloat.__mul__,因为类型层次结构的进化。

完整来源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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

这里有两个问题

  • 在你的__mul__实施MyFloatExt时,你从不检查other是否是MyFloatExt的实例。

  • 由于MyFloatExt继承自MyFloat,因此isinstance(e, MyFloat)始终是正确的。

  • 修复它:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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)