如何在python3中继承复杂

时间:2018-02-06 12:06:24

标签: python-3.x inheritance

我在复杂的飞机上进行优化,功能昂贵。

我希望有一个复杂数字的类,它的行为类似于算术的复数,但也有该函数的结果,并且还有一些方便的调试助手。< / p>

我把以下内容放在一起,直到后来我意识到我不明白为什么它应该起作用,因为我最初省略了对super().__init__()的调用。我不明白z参数是如何设置数字的.real和.imag部分,或者它不会向我抛出错误。当我添加super()时,它仍然完全相同。但是,超级没有参与,所以我不知道如何将参数z变成.real和.imag。

def spam(z):
    return abs(pow(z,3))

class Point(complex):
    def __init__(self, z):
        # super().__init__()    # doesn't seem to make any difference
        # super().__init__(z)   # throws an error

        try:
            Point.serial += 1
        except AttributeError:
            Point.serial = 0
        self.id = Point.serial

        self.y = spam(z)
        self.ge3 = self.y>=3       

    def __str__(self):
        return 'point {} ({}+{}j) = {} {}'.format(self.id,
                                                  self.real,
                                                  self.imag,
                                                  self.y,
                                                  ('below', 'above')[self.ge3])

p = Point(3)
q = Point(2j)
r = Point((p+q)/2)
print(p)
print(q)
print(r)

给出

point 0 (3.0+0.0j) = 27 above
point 1 (0.0+2.0j) = 8.0 above
point 2 (1.5+1.0j) = 5.859020822628983 above

这是合法的还是预期的行为?它是如何工作的?我应该采用不同的方式吗?是否可能停止使用未来版本(目前为3.5.2)?

1 个答案:

答案 0 :(得分:2)

简短回答

你的代码很好,从__new__继承的神奇方法complex是实际创建对象的方法,实际上在对象初始化之前它被称为

尽管如此,调用super().__init__()仍然是一种更好的做法。

答案很长

方法__init__不会创建您的对象,它只会在创建后初始化它。创建它的方法称为__new__。看看下面的代码。

class Point(complex):
    def __init__(self, z):
        print(self)

x = Point(1+1j) # This prints (1+1j)

调用__init__时,已创建对象。但是如果我们要覆盖__new__方法,那么会发生什么。

class Point(complex):
    def __new__(*args):
        return 0 # We purposedly return without calling super().__new__(*args)

    def __init__(self, z):
        print(self)

x = Point(1+1j) # x has value 0

x.imag # That fails

我们确实无法调用x.imag,因为complex.__new__从未被调用过。请注意,此处甚至没有调用__init__,我们将在下面看到原因。

在您的代码中,调用方法complex.__new__(即使用参数z)并返回complex子类为Point,然后传递为self__init__

一般来说,流程如下:

    当你执行MyType.__new__并返回一个对象时,会调用
  1. MyType(...)
  2. 如果MyType.__new__返回的对象是MyType的实例,则会将其作为self传递给MyType.__init__
  3. 否则,MyType.__init__根本就没有被调用,这就是我们看到的第二个例子中发生的事情
  4. 您实际上需要覆盖__new__方法很少见。由于您无法真正创建对象,因此除了调用super().__new__中无法完成的type method__init__之外,您几乎无法做到。它涉及metaclass, which are a lot of fun时非常有用。