在 __init__ 中使用继承的 class 方法
Use inherited class method within __init__
我有一个 parent class 被几个 children 继承。我想使用 parent 的 @classmethod
初始化程序来初始化 children 之一。我怎样才能做到这一点?我试过了:
class Point(object):
def __init__(self,x,y):
self.x = x
self.y = y
@classmethod
def from_mag_angle(cls,mag,angle):
x = mag*cos(angle)
y = mag*sin(angle)
return cls(x=x,y=y)
class PointOnUnitCircle(Point):
def __init__(self,angle):
Point.from_mag_angle(mag=1,angle=angle)
p1 = Point(1,2)
p2 = Point.from_mag_angle(2,pi/2)
p3 = PointOnUnitCircle(pi/4)
p3.x #fail
如果你尝试这样写 __init__
,你的 PointOnUnitCircle
与 Point
有不同的接口(因为它需要 angle
而不是 x, y
) 因此不应该是它的子class。怎么样:
class PointOnUnitCircle(Point):
def __init__(self, x, y):
if not self._on_unit_circle(x, y):
raise ValueError('({}, {}) not on unit circle'.format(x, y))
super(PointOnUnitCircle, self).__init__(x, y)
@staticmethod
def _on_unit_circle(x, y):
"""Whether the point x, y lies on the unit circle."""
raise NotImplementedError
@classmethod
def from_angle(cls, angle):
return cls.from_mag_angle(1, angle)
@classmethod
def from_mag_angle(cls, mag, angle):
# note that switching these parameters would allow a default mag=1
if mag != 1:
raise ValueError('magnitude must be 1 for unit circle')
return super(PointOnUnitCircle, cls).from_mag_angle(1, angle)
这使接口保持不变,添加了检查子class 输入的逻辑(一旦你编写了它!)并提供了一个新的 class 方法来轻松构建一个新的PointOnUnitCircle
来自 angle
。而不是
p3 = PointOnUnitCircle(pi/4)
你必须写
p3 = PointOnUnitCircle.from_angle(pi/4)
您可以覆盖 subclass 的 __new__
方法以从 superclass 的替代构造函数构造实例,如下所示。
import math
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def from_polar(cls, radius, angle):
x = radius * math.cos(angle)
y = radius * math.sin(angle)
return cls(x, y)
class PointOnUnitCircle(Point):
def __new__(cls, angle):
point = Point.from_polar(1, angle)
point.__class__ = cls
return point
def __init__(self, angle):
pass
请注意,在 __new__
中,行 point = Point.from_polar(1, angle)
不能替换为 point = super().from_polar(1, angle)
,因为 Point
将其自身作为备用构造函数的第一个参数发送,super()
将 subclass PointOnUnitCircle
发送到备用构造函数,该构造函数循环调用调用它的 subclass 的 __new__
,依此类推直到 RecursionError
发生。另请注意,即使 __init__
在 subclass 中为空,但没有覆盖 subclass 中的 __init__
,superclass 的 __init__
将在 __new__
后立即自动调用,撤消备用构造函数。
或者,一些对象设计的组合比继承更简单。例如,您可以在不覆盖 __new__
的情况下将上面的 PointOnUnitCircle
class 替换为以下 class.
class UnitCircle:
def __init__(self, angle):
self.set_point(angle)
def set_point(self, angle):
self.point = Point.from_polar(1, angle)
我有一个 parent class 被几个 children 继承。我想使用 parent 的 @classmethod
初始化程序来初始化 children 之一。我怎样才能做到这一点?我试过了:
class Point(object):
def __init__(self,x,y):
self.x = x
self.y = y
@classmethod
def from_mag_angle(cls,mag,angle):
x = mag*cos(angle)
y = mag*sin(angle)
return cls(x=x,y=y)
class PointOnUnitCircle(Point):
def __init__(self,angle):
Point.from_mag_angle(mag=1,angle=angle)
p1 = Point(1,2)
p2 = Point.from_mag_angle(2,pi/2)
p3 = PointOnUnitCircle(pi/4)
p3.x #fail
如果你尝试这样写 __init__
,你的 PointOnUnitCircle
与 Point
有不同的接口(因为它需要 angle
而不是 x, y
) 因此不应该是它的子class。怎么样:
class PointOnUnitCircle(Point):
def __init__(self, x, y):
if not self._on_unit_circle(x, y):
raise ValueError('({}, {}) not on unit circle'.format(x, y))
super(PointOnUnitCircle, self).__init__(x, y)
@staticmethod
def _on_unit_circle(x, y):
"""Whether the point x, y lies on the unit circle."""
raise NotImplementedError
@classmethod
def from_angle(cls, angle):
return cls.from_mag_angle(1, angle)
@classmethod
def from_mag_angle(cls, mag, angle):
# note that switching these parameters would allow a default mag=1
if mag != 1:
raise ValueError('magnitude must be 1 for unit circle')
return super(PointOnUnitCircle, cls).from_mag_angle(1, angle)
这使接口保持不变,添加了检查子class 输入的逻辑(一旦你编写了它!)并提供了一个新的 class 方法来轻松构建一个新的PointOnUnitCircle
来自 angle
。而不是
p3 = PointOnUnitCircle(pi/4)
你必须写
p3 = PointOnUnitCircle.from_angle(pi/4)
您可以覆盖 subclass 的 __new__
方法以从 superclass 的替代构造函数构造实例,如下所示。
import math
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def from_polar(cls, radius, angle):
x = radius * math.cos(angle)
y = radius * math.sin(angle)
return cls(x, y)
class PointOnUnitCircle(Point):
def __new__(cls, angle):
point = Point.from_polar(1, angle)
point.__class__ = cls
return point
def __init__(self, angle):
pass
请注意,在 __new__
中,行 point = Point.from_polar(1, angle)
不能替换为 point = super().from_polar(1, angle)
,因为 Point
将其自身作为备用构造函数的第一个参数发送,super()
将 subclass PointOnUnitCircle
发送到备用构造函数,该构造函数循环调用调用它的 subclass 的 __new__
,依此类推直到 RecursionError
发生。另请注意,即使 __init__
在 subclass 中为空,但没有覆盖 subclass 中的 __init__
,superclass 的 __init__
将在 __new__
后立即自动调用,撤消备用构造函数。
或者,一些对象设计的组合比继承更简单。例如,您可以在不覆盖 __new__
的情况下将上面的 PointOnUnitCircle
class 替换为以下 class.
class UnitCircle:
def __init__(self, angle):
self.set_point(angle)
def set_point(self, angle):
self.point = Point.from_polar(1, angle)