在Python中将对象从类转换为子类的方法

时间:2015-11-19 12:15:38

标签: python object inheritance casting subclass

考虑以下最小问题:

from math import sqrt    

class Vector(object):

    def __init__(self, x, y, z):
        self.v = [x, y, z]

    def normalize(self):
        x, y, z = self.v
        norm = sqrt(x**2 + y**2 + z**2)
        self.v = [x/norm, y/norm, z/norm]

    # other methods follow  

class NormalizedVector(Vector):

    def __init__(self, x, y, z):
        super(Vector, self).__init__(x, y, z)
        self.normalize()

因此,基本上NormalizedVector对象与Vector对象相同,但添加了规范化。

是否可以向Vector添加一个方法,以便每当调用normalize方法时,对象会自动子类化为NormalizedVector?

我知道我可以使用abstract factory pattern,但这只有在创建时对象被子类化时才会起作用:我希望能够创建先前已创建的对象的子类。

我发现some solutions基于重新分配__ class __方法,但不建议这样做。我愿意将上面的模式修改为更“Pythonic”的模式。

3 个答案:

答案 0 :(得分:2)

我建议只使用 Vector()类和布尔normalized实例属性。

此外,在normalize方法中,您使用的是 x y z ,但这些变量未定义且您是甚至没有用self阅读它们。

我建议的代码:

from math import sqrt    

class Vector(object):

    def __init__(self, x, y, z, normalized=False):
        self.v = [x, y, z]
        if normalized in [True, False]:
            self.normalized = normalized
        else:
            raise Exception("Please set normalized to either True or False")

    def __repr__(self):
        return "Vector ({}, {}, {})".format(*self.v)

    def normalize(self):
        x,y,z = self.v
        norm = sqrt(x**2 + y**2 + z**2)
        self.v = [x/norm, y/norm, z/norm]
        self.normalized = True

    def isNormalized(self):
        return self.normalized

    # other methods follow  

v1 = Vector(10, 20, 30)
print v1.isNormalized()
v1.normalize()
print v1.isNormalized()

v2 = Vector(40, 50, 60, normalized=True)
print v2.isNormalized()

<强>输出:

False
True
True

__ repr __ 功能只会显示您对象的良好表现形式:

print v1

<强>输出:

Vector (0.267261241912, 0.534522483825, 0.801783725737)

答案 1 :(得分:1)

为什么需要跟踪矢量本身的规范化,只需在main.py或您使用矢量的任何地方跟踪它?

另外,我只是返回带有规范化值的对象的新副本。这样,您可以在计算中动态创建标准化向量,而无需更改原始向量。

from math import sqrt    

class Vector(object):

    def __init__(self, x, y, z):
        self.v = [x, y, z]

    def normalized(self):
        x, y, z = self.v
        norm = sqrt(x**2 + y**2 + z**2)
        return Vector(x/norm, y/norm, z/norm)

如果你有很多矢量你需要规范化,你可以将它们规范化为两个列表或一个元组列表或任何你想要的,这是一个字典的例子:

vectors = {}
for x, y, z in zip(range(10), range(10), range(10)):
    v = Vector(x, y, z)
    vectors[v] = v.normalize()

如果您只是有一些向量或随机需要对矢量进行标准化以进行计算,您可以手动跟踪它们或在计算中动态创建它们而不更改原始向量:{{ 1}}。

答案 2 :(得分:0)

如果你真的想保留这两个类,你可以覆盖这些类的操作。

我们假设您要添加向量和规范化向量。你可以这样做

来自math import sqrt

class Vector:

    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __add__(self,v):
        if isinstance(v,Vector):
            return (self.x+v.x,self.y+v.y)
        elif isinstance(v,NormVector):
            n = NormVector(self.x,self.y)
            return (n.x+v.x,n.y+v.y)

class NormVector:

    def __init__(self,x,y):
        self.x = x / sqrt(x**2 + y**2)
        self.y = y / sqrt(x**2 + y**2)

    def __add__(self,v):
        if isinstance(v,Vector):
            n = NormVector(v);
            return (self.x + n.x,self.y + n.y)
        elif isinstance(v,NormVector):
            return (self.x+v.x,self.y+v.y)


a = Vector(5,0)
b = NormVector(0,3)
c = a + b
print c

像这样你可以覆盖你需要的任何功能。您可以在documentation

中找到可能的操作列表