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

3
考虑以下最小化问题:
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?
我知道我可以使用抽象工厂模式,但这仅在创建时对对象进行子类化时才起作用:我希望能够对先前已创建的对象进行子类化。
我发现一些解决方案基于重新分配__ class __方法,但这些被不鼓励使用。我愿意修改上述模式,使其更具“Pythonic”。

3
为什么不仅使用带有布尔型normalized实例属性的向量类? - Andrés Pérez-Albela H.
3个回答

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,0,0),但这取决于代码使用者是否认为这很重要。此外,如果任何操作改变了实例,这个属性需要被重置。 - Caramiriel
@Caramiriel,然后(如我所更新的),设置一个带有default=Falsenormalized关键字参数,如果他想将向量初始化为normalized,则可以在构造函数中指定。 - Andrés Pérez-Albela H.

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()

如果您只有少量向量或偶尔需要规范化向量以进行计算,您可以手动跟踪它们或在计算中即时创建它们,而不更改原始向量:v_norm = v.normalized()

0
如果你真的想保留这两个类,你可以重写这两个类的操作。
假设你想要添加向量和归一化向量,你可以像这样做:
从math库中导入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

你可以像这样覆盖掉任何需要的函数。你可以在文档中找到可能操作的列表。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接