【问题标题】:Method to convert object from class to subclass in PythonPython中将对象从类转换为子类的方法
【发布时间】:2016-02-21 14:03:25
【问题描述】:

考虑以下最小问题:

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 基于重新分配 __ 类 __ 方法,但不鼓励这样做。我愿意将上面的模式修改为更“Pythonic”的模式。

【问题讨论】:

  • 为什么不只使用带有布尔 normalized 实例属性的 Vector 类?

标签: python object inheritance casting subclass


【解决方案1】:

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

另外,在normalize 方法中,您使用的是 xyz,但这些变量没有定义,您甚至没有用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,然后(正如我更新的那样)设置一个 normalized kwarg 和 default=False,如果他想将 de Vector 初始化为 normalized,他可以在构造函数。
【解决方案2】:

为什么您需要跟踪向量本身的规范化,只需在您的 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)

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

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

如果您只有几个向量,或者不时需要对向量进行归一化计算,您可以手动跟踪它们或在计算中动态创建它们,而无需更改原始向量:@987654324 @。

【讨论】:

    【解决方案3】:

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

    假设您要添加向量和归一化向量。你可以这样做

    从数学导入 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

    中找到可能的操作列表

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-03
      • 2022-09-29
      • 1970-01-01
      • 2020-07-10
      相关资源
      最近更新 更多