Python-2.7 class 方法导致对象成为

Python-2.7 class method causing objects to be

我在编写 class 定义时遇到问题,该定义导致调用 class 方法的对象发生更改。这种更改对象的行为是不可取的。我希望 class 方法能够将两个对象加在一起并吐出一个相同类型的新对象,即 a = b+c

我的 class 加法定义创建了一个 class 类型的新实例来保存两个对象组合的结果。麻烦的是,完成后,调用对象被更改为与两个对象的总和相同。

下面显示了不良行为的最小工作示例。该代码创建了 class 的两个实例,并使用一些随机数据对它们进行了初始化。每个对象包含两个等长列表和一个保存列表长度的整数。然后主代码打印每个对象的内容,调用addition方法并将数据存储到新对象中,最后打印原始对象的内容。

我在为 class 创建初始化时遇到了默认可变参数的问题 运行。我在想这是我不理解 Python 代码中何时发生可变行为以及如何防止它发生的另一个案例。

class myClass:

        def __init__(self,list_a=None,list_b=None,list_count=0):
                self.list_a=[] if list_b is None else list_a
                self.list_b=[] if list_b is None else list_b
                self.list_count = list_count

        def add_data(self,ElementA,ElementB):
                self.list_a.append(ElementA)
                self.list_b.append(ElementB)
                self.list_count = self.list_count + 1

        def print_data(self):
                print("Number of elements in this object is: %d"%self.list_count)
                print("List A contents\n%s"%self.list_a)
                print("List B contents\n%s\n"%self.list_b)

        def addTogether(self,other):
                test_data = myClass(self.list_a,self.list_b,self.list_count)

                for i in range(0,other.list_count):
                        test_data.add_data(other.list_a[i],other.list_b[i])

                return(myClass(test_data.list_a,test_data.list_b,test_data.list_count))

import random

object_array = [myClass() for i in range(2)]
#Loop over object array and fill each object with some data
for i in range(0,2):

        NumData = int(10*random.random())
        for m in range(0,NumData):
                #Generate some junk data to insert into the list of this object
                ListAData = int(10*random.random())
                ListBData = int(10*random.random())

                object_array[i].check_data()
                object_array[i].add_data(ListAData,ListBData)
                object_array[i].check_data()

object_array[0].print_data()
object_array[1].print_data()

new_data = object_array[0].addTogether(object_array[1])
new_data.print_data()

object_array[0].print_data()
object_array[1].print_data()

代码输出:

Number of elements in this object is: 2
List A contents
[6, 5]
List B contents
[8, 7]

Number of elements in this object is: 2
List A contents
[7, 6]
List B contents
[5, 3]

Number of elements in this object is: 4
List A contents
[6, 5, 7, 6]
List B contents
[8, 7, 5, 3]

Number of elements in this object is: 2
List A contents
[6, 5, 7, 6]
List B contents
[8, 7, 5, 3]

Number of elements in this object is: 2
List A contents
[7, 6]
List B contents
[5, 3]

对于 "defend" 传入列表,这些列表只是对对象的引用,只需在构造时对它们进行浅复制:

self.ListA=[] if ListA is None else ListA[:]
self.ListB=[] if ListB is None else ListB[:]

请注意,mylist[:] 复制列表(但不是内部对象,所以这是一个浅拷贝),并保护对现有源列表的任何外部引用。

目前您正在更改您在施工时获得的列表。

示例:

List A contents
[1, 7, 6, 9, 8, 8, 5, 0]
List B contents
[8, 9, 3, 5, 1, 3, 1, 8]

Number of elements in this object is: 8
List A contents
[7, 3, 1, 3, 9, 2, 8, 0]
List B contents
[8, 6, 6, 5, 0, 1, 8, 9]

Number of elements in this object is: 16
List A contents
[1, 7, 6, 9, 8, 8, 5, 0, 7, 3, 1, 3, 9, 2, 8, 0]
List B contents
[8, 9, 3, 5, 1, 3, 1, 8, 8, 6, 6, 5, 0, 1, 8, 9]

Number of elements in this object is: 8
List A contents
[1, 7, 6, 9, 8, 8, 5, 0]
List B contents
[8, 9, 3, 5, 1, 3, 1, 8]

Number of elements in this object is: 8
List A contents
[7, 3, 1, 3, 9, 2, 8, 0]
List B contents
[8, 6, 6, 5, 0, 1, 8, 9]

问题是您正在使用对象 A 中的列表而没有复制它们,因此当它们被更改时,原始列表也会被更改。可以找到许多解决此问题的方法 here. 我更喜欢使用 list()。这将使您的 addTogether 方法如下所示:

def addTogether(self,other):
        TestData = myClass(list(self.ListA),list(self.ListB),self.ListCount)

        for i in range(0,other.ListCount):
                TestData.add_data(other.ListA[i],other.ListB[i])

        return(TestData)

您似乎在维护两个并行数组。通常这不是一个好主意。我建议考虑创建一个对象,其中包含存储在列表 A 和列表 B 中的数据的属性。然后您可以创建这些列表。合并列表就变得微不足道了。

你没看错,是同一个列表。使用 [:] 复制它,对我有用。

    def addTogether(self,other):
            TestData = myClass(self.ListA[:],self.ListB[:],self.ListCount)

            for i in range(0,other.ListCount):
                    TestData.add_data(other.ListA[i],other.ListB[i])

            return TestData