在初始化父类之前修改继承类的输入参数

时间:2014-02-18 04:01:01

标签: python class inheritance input

我一直在创建一个几何模块。我已经定义了GeoTuple,Vector(GeoTuple),Normal(Vector)。因为法线必须具有1的大小,所以我需要获取输入参数并在启动Vector之前修改它们,请参阅下面的代码:

class GeoTuple(tuple, object):
    def __init__(self, data):
        try:
            if len(data) != 3:
                raise ValueError("Vector must have 3 members only")
            _floats = tuple(float(item) for item in data)
            super(GeoTuple, self).__init__(_floats)
        finally:
            pass

    def __add__(self, b):
        raise NameError("Concatenation has been disabled for GeoTuple")

    def __mul__(self, b):
        raise NameError("Shallow Copeis has been disabled for GeoTuple")


class Vector(GeoTuple, object):
    def __init__(self,point):
        super(Vector, self).__init__(point)


    @property
    def x(self):
        return self[0]

    @property
    def y(self):
        return self[1]

    @property
    def z(self):
        return self[2]

    @property
    def magnitude(self):
        _x, _y, _z = self
        return sqrt(_x**2 + _y**2 + _z**2)


    def __add__(self, b):
        _p = (self.x + b.x, self.y + b.y, self.z + b.z)
        return Vector(_p)


    def __sub__(self, b):
        _p = (self.x - b.x, self.y - b.y, self.z - b.z)
        return Vector(_p)


    def __mul__(self, b):
        if isinstance(b, self.__class__):
            _s = self.x*b.x + self.y*b.y + self.z*b.z
            result = _s
        else:
            _s = float(b)
            _p = (self.x*_s, self.y*_s, self.z*_s)
            result = Vector(_p)
        return result


    def __abs__(self):
        return Vector((abs(self.x),abs(self.y),abs(self.z)))


    def __neg__(self):
        return Vector((-self.x, -self.y, -self.z))


    def cross(self, b):
        _p = [self.y*b.z - self.z*b.y, self.z*b.x - self.x*b.z, 
            self.x*b.y - self.y*b.x]
        return Vector(_p)


    def __xor__(self, b):
        return self.cross(b)


class Normal(Vector, object):
    def __init__(self, data):
        _x, _y, _z = data
        _mag = sqrt(_x**2 + _y**2 + _z**2)
        _p = [_x/_mag, _y/_mag, _z/_mag]
        super(Vector, self).__init__(_p)

问题是,如果我打电话:

n1 = Normal([1,3,8])
n1

它返回:

(1,3,8)

(0.11624763874381928, 0.34874291623145787, 0.9299811099505543)

编辑1

我在正常情况下将参数名称从点更改为数据(这只是一个复制粘贴错误)。 GeoTuple必须保持不变,所以听起来像 new 是实现它的方法吗?你能提供一个具体的例子吗?

3 个答案:

答案 0 :(得分:1)

元组是不可变的,因此试图在__init__中更改它有点晚了。要么覆盖__new__,要么将基类更改为可变列表。

这有效:

class GeoTuple(list, object): #list not tuple

....

class Normal(Vector, object):
    def __init__(self, point):
        _x, _y, _z = point #same name as param
        _mag = (_x**2 + _y**2 + _z**2)**.5
        _p = [_x/_mag, _y/_mag, _z/_mag]
        super(Normal, self).__init__(_p) #right class name

n1 = Normal([1,3,8])
print n1

输出是:

[0.11624763874381928, 0.34874291623145787, 0.9299811099505543]

答案 1 :(得分:0)

从普通中移除__init__并添加__new__,我就能实现我的目标。

class Normal(Vector, object):

    def __new__(self, data):
        _x, _y, _z = data
        _mag = sqrt(_x**2 + _y**2 + _z**2)
        _p = [_x/_mag, _y/_mag, _z/_mag]
        return Vector.__new__(self,_p)

答案 2 :(得分:-1)

底层数据结构(元组,列表或其他内容)之间的实际选择取决于这些对象的使用方式。如果您可以使用不可变数据,则可以使用tuple并覆盖用户@hansonap建议的__new__()方法。如果您需要修改数据(可能)并且能够在单个Point中扩展存储实体的数量(不太可能),您可以将tuple更改为list。但是如果您需要{em>批次 Point s,那么您可以将array视为基础数据存储等。此外,如果您的程序中需要大量数学,你可以看一下NumPy