繁体   English   中英

在 __init__ 中使用继承的类方法

[英]Use inherited class method within __init__

我有一个由几个孩子继承的父类。 我想使用父级的@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

如果您尝试像这样编写__init__ ,则您的PointOnUnitCirclePoint具有不同的接口(因为它采用angle而不是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)

这使界面保持不变,添加了检查子类输入的逻辑(一旦你写好了!)并提供一个新的类方法来轻松地从一个angle构造一个新的PointOnUnitCircle 而不是

p3 = PointOnUnitCircle(pi/4)

你必须写

p3 = PointOnUnitCircle.from_angle(pi/4)

您可以覆盖子类的__new__方法以从超类的备用构造函数构造实例,如下所示。

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()的第一个参数发送将子类PointOnUnitCircle发送到备用构造函数,该构造函数循环调用调用它的子类的__new__ ,依此类推,直到发生RecursionError 还要注意的是,即使__init__是在子类空的,没有覆盖__init__在子类中,超类的__init__将自动后立即叫__new__ ,撤消可选的构造。

或者,某些对象设计的组合比继承更简单。 例如,您可以替换上面的PointOnUnitCircle类而不用以下类覆盖__new__

class UnitCircle:

    def __init__(self, angle):
        self.set_point(angle)

    def set_point(self, angle):
        self.point = Point.from_polar(1, angle)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM