如何返回类实例的副本?

时间:2019-06-09 06:27:10

标签: python

我目前正在针对代码战争练习python,这是一个提示:

创建一个Vector对象,该对象支持加,减,点积和范数。因此,例如:

    a = Vector([1, 2, 3])
    b = Vector([3, 4, 5])
    c = Vector([5, 6, 7, 8])

    a.add(b)      # should return a new Vector([4, 6, 8])
    a.subtract(b) # should return a new Vector([-2, -2, -2])
    a.dot(b)      # should return 1*3 + 2*4 + 3*5 = 26
    a.norm()      # should return sqrt(1^2 + 2^2 + 3^2) = sqrt(14)
    a.add(c)      # raises an exception

我已经编写了通过一些测试通过的加法和减法函数。但是,在运行add函数之后,我覆盖了以前的列表值“ a”时遇到了问题。当我进行减法运算时,vector中的'a'值是根据加法函数的先前实例计算得出的总和。

我怀疑这是由于我运行了以下代码行: return self.__class__(self.list)导致类的实例覆盖自身。

请帮助,我相信我需要返回该类实例的副本,但不知道该怎么做。

    class Vector:

      def __init__(self, list):

          self.list = list #[1,2]
          self.copylist = list

      def add(self,Vector):

          try:
              self.list = self.copylist

              #take list from other vector
              other = Vector.list

              #take each value from other Vector and add it to self.list
              for index,item in enumerate(Vector.list,0):
                  self.list[index] = item + self.list[index]


          except:
              print("Different size vectors")
          #return the instance of a class
          return self.__class__(self.list)

       def subtract(self,Vector):

          self.list = self.copylist
          other = Vector.list

          print(self.list)
          print(other)

          for index,item in enumerate(Vector.list,0):
              self.list[index] = self.list[index] - item

          return self.__class__(self.list)

       def dot(self,Vector):
          self.list = self.copylist
          other = Vector.list

          #print(self.list)
          #print(other)

          running_sum =0

          for index,item in enumerate(Vector.list,0):
              running_sum = running_sum + item * self.list[index]
              #print(running_sum, " ", self.list[index], " ", item)

          return running_sum

       def norm(self):
          running_sum = 0

          for item in self.list:
              running_sum += item**2

          return running_sum ** 0.5

       def toString(self):
          return str(self.list)

      `def equals(self,Vector):
          return self.list == Vector.list

以下是一些测试:

    a = Vector([1, 2])
    b = Vector([3, 4])

    test.expect(a.add(b).equals(Vector([4, 6])))


    a = Vector([1, 2, 3])
    b = Vector([3, 4, 5])

    test.expect(a.add(b).equals(Vector([4, 6, 8])))
    test.expect(a.subtract(b).equals(Vector([-2, -2, -2]))) #code fails here
    test.assert_equals(a.dot(b), 26)
    test.assert_equals(a.norm(), 14 ** 0.5)

2 个答案:

答案 0 :(得分:2)

我认为您正在使这一过程变得比所需的更为复杂。您根本不应该使用类对象。您应该只使用Vector类的实例。我认为您的代码应如下所示:

class Vector:

    def __init__(self, initial_elements):

        self.elements = list(initial_elements) # make a copy of the incoming list of elements

    def add(self, other):

        # insure that the two vectors match in length
        if len(self.elements) != len(other.elements):
            raise Exception("Vector sizes are different")

        # copy our elements
        r = list(self.elements)

        # add the elements from the second vector
        for index, item in enumerate(other.elements, 0):
            r[index] += item

        # return a new vector object defined by the computed elements
        return Vector(r)

    def subtract(self, other):

        # insure that the two vectors match in length
        if len(self.elements) != len(other.elements):
            raise Exception("Vector sizes are different")

        # copy our elements
        r = list(self.elements)

        # subtract the elements from the second vector
        for index, item in enumerate(other.elements, 0):
            r[index] -= item

        # return a new vector object defined by the computed elements
        return Vector(r)

    def dot(self, other):

        running_sum = 0

        for index, item in enumerate(other.elements, 0):
            running_sum += item * self.elements[index]

        return running_sum

    def norm(self):
        running_sum = 0

        for item in self.elements:
            running_sum += item ** 2

        return running_sum ** 0.5

    def toString(self):
        return str(self.elements)

    def equals(self, other):
        return self.elements == other.elements

def test():
    a = Vector([1, 2])
    b = Vector([3, 4])
    print(a.add(b).equals(Vector([4, 6])))

    a = Vector([1, 2, 3])
    b = Vector([3, 4, 5])

    print(a.add(b).equals(Vector([4, 6, 8])))
    print(a.subtract(b).equals(Vector([-2, -2, -2])))
    print(a.dot(b) == 26)
    print(a.norm() == 14 ** 0.5)

test()

结果:

True
True
True
True
True

您的代码的一般结构已经出现。

要注意的一件事是您不应该使用list作为变量名,因为它是Python中的类型名。另外,您也不想传递Vector作为值。您希望传递Vectorlist的实例,这些实例的名称应与这些类型名称不冲突。

我的解决方案假定您希望Vector实例是不可变的,因此您的每个操作都将返回一个新的Vector对象。您也可以使它们不是一成不变的,例如,add方法仅将传入向量添加到目标向量中,而无需创建新对象。我喜欢保持它们不变。最近,我越来越多地进行这种“功能风格”编程,其中对对象方法的调用不会修改目标对象(没有副作用),而只是返回一个新对象。

我喜欢您使用test类进行测试。我选择不处理此问题,仅打印每个测试比较的结果以查看它们全部出现在True中。我将它留给您,以将您的测试还原为使用具有expectassert_equals方法的测试对象。<​​/ p>

更新:这是编写addsubtract方法的更紧凑的方法:

def add(self, other):

    # insure that the two vectors match in length
    if len(self.elements) != len(other.elements):
        raise Exception("Vector sizes are different")

    return Vector([self.elements[i] + other.elements[i] for i in range(len(self.elements))])

def subtract(self, other):

    # insure that the two vectors match in length
    if len(self.elements) != len(other.elements):
        raise Exception("Vector sizes are different")

    return Vector([self.elements[i] - other.elements[i] for i in range(len(self.elements))])

答案 1 :(得分:0)

更改:

return self.__class__(self.list)

收件人:

return self

尽管这与

相同
return Vector(self.list)

如果类更复杂,最好返回self

我认为这就是问题所在,希望对您有所帮助:)

此外,优良作法是使用其他名称。您将Vector用作类名以及函数的许多输入,这样做会遇到问题。