Python 在_init中使用继承的类方法__
我有一个由几个孩子继承的父类。我想使用父级的Python 在_init中使用继承的类方法__,python,inheritance,class-method,Python,Inheritance,Class Method,我有一个由几个孩子继承的父类。我想使用父级的@classmethod初始值设定项初始化其中一个子级。我该怎么做?我试过: 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*si
@classmethod
初始值设定项初始化其中一个子级。我该怎么做?我试过:
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
如果您尝试这样编写
\uuuu init\uuuu
,您的PointOnUnitCircle
与Point
具有不同的接口(因为它需要角度,而不是x,y
),因此不应该是它的子类。比如说:
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)
这使接口保持不变,添加了检查子类输入的逻辑(一旦编写了它!),并提供了一个新的类方法,可以从角度轻松构建新的PointOnUnitCircle
。而不是
p3 = PointOnUnitCircle(pi/4)
你必须写作
p3 = PointOnUnitCircle.from_angle(pi/4)
您可以重写子类的\uuuu new\uuu
方法,以从超类的备用构造函数构造实例,如下所示
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
请注意,在\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
中,行point=point.from\uPolar(1,angle)
不能替换为point=super()。from\uPolar(1,angle)
是因为point
作为备用构造函数的第一个
将子类PointOnUnitCircle
发送到备用构造函数,该构造函数循环调用调用它的子类的\uuuuuuu new\uuuuuu
,依此类推,直到发生递归错误。还要注意的是,即使子类中的\uuuuuu init\uuuu
为空,但在子类中不重写\uuuuuuu init\uuuu
的情况下,超类的\uuuu init\uuuuu
会在\uuu new\uuuu
之后立即自动调用,从而撤消备用构造函数
或者,某些对象设计使用组合比使用继承更简单。例如,您可以替换上面的PointOnUnitCircle
类,而不使用以下类重写\uuuu new\uuuu
class UnitCircle:
def __init__(self, angle):
self.set_point(angle)
def set_point(self, angle):
self.point = Point.from_polar(1, angle)
@classmethod
和self
?!类方法的第一个参数通常命名为cls
,以区别于实例self
。您当然可以通过self
访问类方法,但在本例中,由于类方法设置了一个class属性,因此不清楚您为什么要访问类方法。您不能在\uuu init\uuu
中分配给self
,并期望它能正常工作。如果类方法是替代构造函数,为什么不直接使用A10.from_half_a(5)
?类方法调用\uuuuuu init\uuuu
,而不是相反。继承已经实现了您想要的功能,因为您在继承的方法中使用了cls(…)
而不是A(…)
。@alex这不是意见问题!当您从类方法内部调用cls(…)
时,该类方法对cls
表示的任何类调用\uuuuu init\uuuuu
(和/或\uuuuu new\uuuuuuuu
),创建一个新实例。“我试图做的只是从子类使用父类的替代构造函数”,因此,再次使用ChildClass.inherited\u class\u方法(…)
。例如,请参阅,了解为什么不能分配给self
。这正是我的答案所讨论的问题。您的“子类”现在与父类具有完全不同的签名,如果您从_polar
直接调用它,则会发生不好的事情。不能只在使用父对象的地方使用它。这个实现是多么笨拙,这暗示了它是一个坏主意。我必须把从_polar
变成一个静态方法来解决这个问题,这可能会导致更多的问题。放弃与super
的兼容性,进入\uuuuuuuuuu新的和\uuuuuuuuuu类
似乎是危险信号。我很高兴你指出了缺陷。如果子类只对超类的替代构造函数有意义,那么最好使用组合,因为即使使用您提供的无褶皱解决方案,子类的正常构造也不再有用,从这个意义上讲,正如您所说,“您不能在使用父类的任何地方使用它。”