我在复杂的飞机上进行优化,功能昂贵。
我希望有一个复杂数字的类,它的行为类似于算术的复数,但也有该函数的结果,并且还有一些方便的调试助手。< / 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)?
答案 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__
并返回一个对象时,会调用MyType(...)
MyType.__new__
返回的对象是MyType
的实例,则会将其作为self
传递给MyType.__init__
MyType.__init__
根本就没有被调用,这就是我们看到的第二个例子中发生的事情您实际上需要覆盖__new__
方法很少见。由于您无法真正创建对象,因此除了调用super().__new__
中无法完成的type method或__init__
之外,您几乎无法做到。它涉及metaclass, which are a lot of fun时非常有用。